diff options
Diffstat (limited to 'src/dns.erl')
-rw-r--r-- | src/dns.erl | 93 |
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. |