summaryrefslogtreecommitdiff
path: root/src/dns.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/dns.erl')
-rw-r--r--src/dns.erl93
1 files changed, 73 insertions, 20 deletions
diff --git a/src/dns.erl b/src/dns.erl
index b8a8ffe..f327a8f 100644
--- a/src/dns.erl
+++ b/src/dns.erl
@@ -3,10 +3,10 @@
-module(dns).
-export([decode_rrset/1, decode_rr/1, encode_rrset/1, encode_rr/1,
- canonicalize_dsrr/2]).
+ canonicalize/1, validate/1]).
-record(rr, {name :: list(), % List of name labels.
- type :: binary(),
+ type :: non_neg_integer(),
class :: binary(),
ttl :: integer(),
rdata :: binary()}).
@@ -14,8 +14,15 @@
-spec decode_name_label(binary()) -> tuple().
decode_name_label(RRbin) ->
- <<Len:8/integer, Label:Len/binary, Rest/binary>> = RRbin,
- {binary_to_list(Label), Rest}.
+ <<IsPtr:2/integer, _:6/integer, _/binary>> = RRbin,
+ case IsPtr of
+ 0 ->
+ <<_:2/integer, Len:6/integer, Label:Len/binary, Rest/binary>> = RRbin,
+ {binary_to_list(Label), Rest};
+ _ ->
+ <<_:2/integer, _Ptr:14/integer, Rest/binary>> = RRbin,
+ {'*compressed*', Rest}
+ end.
-spec encode_name_label(string()) -> binary().
encode_name_label(Label) ->
@@ -40,10 +47,17 @@ encode_name([], Acc) ->
encode_name([H|T], Acc) ->
encode_name(T, [encode_name_label(H) | Acc]).
+has_compressed_name_p(Name) ->
+ lists:any(fun(Label) -> case Label of
+ '*compressed' -> true;
+ _ -> false
+ end
+ end, Name).
+
-spec decode_rr(binary()) -> {rr(), binary()}.
decode_rr(RRBin) ->
{Name, RestRR} = decode_name(RRBin),
- <<Type:2/binary,
+ <<Type:2/integer-unit:8,
Class:2/binary,
TTL:4/integer-unit:8,
RDLength:2/integer-unit:8,
@@ -66,7 +80,7 @@ encode_rr(#rr{name = Name, type = Type, class = Class, ttl = TTL, rdata = RDATA}
EncodedName = encode_name(Name),
RDLength = byte_size(RDATA),
<<EncodedName/binary,
- Type:2/binary,
+ Type:2/integer-unit:8,
Class:2/binary,
TTL:4/integer-unit:8,
RDLength:2/integer-unit:8,
@@ -80,20 +94,59 @@ encode_rrset([], Acc) ->
encode_rrset([H|T], Acc) ->
encode_rrset(T, [encode_rr(H) | Acc]).
-%% Cacnonicalise a single DS RR according to RFC4034 section 6.2.
-canonicalize_dsrr(DS, RRSIG) ->
- %% 1. expand domain name
- %% FIXME: What does a compressed name look like?
-
- %% 2. lowercase
- LCName = lists:map(fun(L) -> string:to_lower(L) end, DS#rr.name),
-
- %% 3. N/A for DS
- %% 4. N/A for DS FIXME: verify
-
- %% 5. set TTL to that of the RRSIG
- OrigTTL = RRSIG#rr.ttl,
+%% Canonicalise a single RR according to RFC4034 section 6.2.
+canonicalize_rr_form(RR, RRSIG) ->
+ %% 1. Expand domain name -- a label with a length field >= 0xC0 is
+ %% a two octet pointer, which we can't expand (since we don't have
+ %% the full message): Do nothing.
+
+ %% 2. Owner name casing: Lowercase.
+ LCName = lists:map(fun string:to_lower/1, RR#rr.name),
+
+ %% 3. DNS names in RDATA casing -- N/A for DS and DNSKEY but
+ %% FIXME: needs to be done for RRSIG?
+
+ %% 4. FIXME: unexpanded owner name
+
+ %% 5. Set TTL to "Original TTL" of the corresponding RRSIG.
+ <<_:4/binary, OrigTTL:32/integer, _/binary>> = RRSIG#rr.rdata,
+
+ RR#rr{name = LCName, ttl = OrigTTL}.
+
+%% Canonicalise an RRset with DNSKEY, DS, and RRSIG records according
+%% to RFC4034 section 6. Records of other types are removed. Duplicate
+%% records are removed.
+canonicalize(RRset) ->
+ %% 6.1 owner name order
+ RRset61 = RRset, % TODO
+
+ %% 6.2 RR form
+ [DS, RRSIG | Rest] = RRset61,
+ C14N_DS = canonicalize_rr_form(DS, RRSIG),
+ RRset62 = [C14N_DS, RRSIG | Rest],
+
+ %% 6.3 RR ordering (and dropping duplicates)
+ RRset63 = RRset62,
+
+ RRset63.
+
+%% Is the RR set valid for our needs from a DNS point of view? If so,
+%% return the signature inception time of the RRSIG covering the DS
+%% RR, to be used as the validation time for the DNSSEC validation.
+-spec validate(binary()) -> {valid, integer()} | {invalid, atom()}.
+validate(RRsetBin) ->
+ [DS, RRSIG | _Rest] = decode_rrset(RRsetBin),
+ case has_compressed_name_p(DS#rr.name) of
+ false when DS#rr.type == 43,
+ RRSIG#rr.type == 46 ->
+ <<_:12/binary, SigInceptionTime:32/integer, _/binary>> =
+ RRSIG#rr.rdata,
+ {valid, SigInceptionTime};
+ false ->
+ {invalid, badtype};
+ true ->
+ {invalid, compressed_name}
+ end.
- DS#rr{name = LCName, ttl = OrigTTL}.
%% TODO: Add unit tests.