Skip to content

Commit

Permalink
inet_dns: support TSIG
Browse files Browse the repository at this point in the history
  • Loading branch information
jimdigriz committed Aug 9, 2023
1 parent 2f6587f commit ffda096
Show file tree
Hide file tree
Showing 9 changed files with 1,178 additions and 6 deletions.
2 changes: 2 additions & 0 deletions lib/kernel/src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ MODULES = \
inet_config \
inet_db \
inet_dns \
inet_dns_tsig \
inet_epmd_dist \
inet_epmd_socket \
inet_gethost_native \
Expand Down Expand Up @@ -268,6 +269,7 @@ $(EBIN)/inet6_sctp.beam: inet_int.hrl
$(EBIN)/inet_config.beam: inet_config.hrl ../include/inet.hrl
$(EBIN)/inet_db.beam: ../include/inet.hrl inet_int.hrl inet_res.hrl inet_dns.hrl inet_config.hrl
$(EBIN)/inet_dns.beam: inet_int.hrl inet_dns.hrl inet_dns_record_adts.hrl
$(EBIN)/inet_dns_tsig.beam: inet_dns.hrl
$(EBIN)/inet_gethost_native.beam: ../include/inet.hrl
$(EBIN)/inet_hosts.beam: ../include/inet.hrl
$(EBIN)/inet_parse.beam: ../include/file.hrl
Expand Down
86 changes: 85 additions & 1 deletion lib/kernel/src/inet_dns.erl
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@
%% RFC 6762: Multicast DNS
%% RFC 6891: Extension Mechanisms for DNS (EDNS0)
%% RFC 7553: The Uniform Resource Identifier (URI) DNS Resource Record
%% RFC 8945: Secret Key Transaction Authentication for DNS (TSIG)

-export([decode/1, encode/1]).
-export([decode_algname/1, encode_algname/1]).

-import(lists, [reverse/1]).

Expand Down Expand Up @@ -253,6 +255,28 @@ decode_rr_section(Opcode, Bin, N, Buffer, RRs) ->
z = Z,
data = D,
do = DnssecOk};
?S_TSIG ->
%% RFC 8945: 5.2. FORMERR if not last
%% RFC 8945: 5.2. FORMERR if more than one dns_rr_tsig
%% (...covered by being last)
Rest =/= <<>> andalso throw(?DECODE_ERROR),
{DR,AlgName} = decode_name(D, Buffer),
?MATCH_ELSE_DECODE_ERROR(
DR,
<<Now:48, Fudge:16, MACSize:16, MAC:MACSize/binary,
OriginalId:16, Error:16,
OtherLen:16, OtherData:OtherLen/binary>>,
#dns_rr_tsig{
domain = Name,
type = Type,
offset = byte_size(Buffer) - byte_size(Bin),
algname = AlgName,
now = Now,
fudge = Fudge,
mac = MAC,
original_id = OriginalId,
error = Error,
other_data = OtherData});
_ ->
{Class,CacheFlush} = decode_class(C),
Data = if
Expand Down Expand Up @@ -347,7 +371,22 @@ encode_res_section(
DO = case DnssecOk of true -> 1; false -> 0 end,
encode_res_section_rr(
Opcode, Bin, Comp, Rs, DName, ?S_OPT, UdpPayloadSize, false,
<<ExtRCode,Version,DO:1,Z:15>>, Data).
<<ExtRCode,Version,DO:1,Z:15>>, Data);
encode_res_section(
Opcode, Bin, Comp,
[#dns_rr_tsig{
domain = DName,
algname = AlgName,
now = Now,
fudge = Fudge,
mac = MAC,
original_id = OriginalId,
error = Error,
other_data = OtherData}]) ->
Data = {AlgName,Now,Fudge,MAC,OriginalId,Error,OtherData},
encode_res_section_rr(
Opcode, Bin, Comp, [], DName, ?S_TSIG, ?S_ANY, false,
<<0:32/signed>>, Data).

encode_res_section_rr(
Opcode, Bin0, Comp0, Rs, DName, Type, Class, CacheFlush, TTL, Data) ->
Expand Down Expand Up @@ -399,6 +438,7 @@ decode_type(Type) ->
?T_UID -> ?S_UID;
?T_GID -> ?S_GID;
?T_UNSPEC -> ?S_UNSPEC;
?T_TSIG -> ?S_TSIG;
?T_IXFR -> ?S_IXFR;
?T_AXFR -> ?S_AXFR;
?T_MAILB -> ?S_MAILB;
Expand Down Expand Up @@ -441,6 +481,7 @@ encode_type(Type) ->
?S_UID -> ?T_UID;
?S_GID -> ?T_GID;
?S_UNSPEC -> ?T_UNSPEC;
?S_TSIG -> ?T_TSIG;
?S_IXFR -> ?T_IXFR;
?S_AXFR -> ?T_AXFR;
?S_MAILB -> ?T_MAILB;
Expand Down Expand Up @@ -833,6 +874,17 @@ encode_data(Comp, _, ?S_CAA, Data)->
_ ->
{encode_txt(Data),Comp}
end;
encode_data(Comp, _, ?S_TSIG, Data)->
{AlgName,Now,Fudge,MAC,OriginalId,Error,OtherData} = Data,
%% Bypass name compression (RFC 8945, section 4.2)
{AlgNameEncoded,_} = encode_name(gb_trees:empty(), 0, AlgName),
MACSize = byte_size(MAC),
OtherLen = byte_size(OtherData),
DataB = <<AlgNameEncoded/binary,
Now:48, Fudge:16, MACSize:16, MAC:MACSize/binary,
OriginalId:16, Error:16,
OtherLen:16, OtherData:OtherLen/binary>>,
{DataB,Comp};
%%
%% sofar unknown or non standard
encode_data(Comp, _Pos, Type, Data) when is_integer(Type) ->
Expand Down Expand Up @@ -972,3 +1024,35 @@ encode_loc_size(X)
Multiplier = round(math:pow(10, Exponent)),
Base = (X + Multiplier - 1) div Multiplier,
<<Base:4, Exponent:4>>.

decode_algname(AlgName) ->
case AlgName of
?T_TSIG_HMAC_MD5 -> ?S_TSIG_HMAC_MD5;
?T_TSIG_GSS_TSIG -> ?S_TSIG_GSS_TSIG;
?T_TSIG_HMAC_SHA1 -> ?S_TSIG_HMAC_SHA1;
?T_TSIG_HMAC_SHA1_96 -> ?S_TSIG_HMAC_SHA1_96;
?T_TSIG_HMAC_SHA224 -> ?S_TSIG_HMAC_SHA224;
?T_TSIG_HMAC_SHA256 -> ?S_TSIG_HMAC_SHA256;
?T_TSIG_HMAC_SHA256_128 -> ?S_TSIG_HMAC_SHA256_128;
?T_TSIG_HMAC_SHA384 -> ?S_TSIG_HMAC_SHA384;
?T_TSIG_HMAC_SHA384_192 -> ?S_TSIG_HMAC_SHA384_192;
?T_TSIG_HMAC_SHA512 -> ?S_TSIG_HMAC_SHA512;
?T_TSIG_HMAC_SHA512_256 -> ?S_TSIG_HMAC_SHA512_256;
_ -> AlgName % raw unknown algname
end.

encode_algname(Alg) ->
case Alg of
?S_TSIG_HMAC_MD5 -> ?T_TSIG_HMAC_MD5;
?S_TSIG_GSS_TSIG -> ?T_TSIG_GSS_TSIG;
?S_TSIG_HMAC_SHA1 -> ?T_TSIG_HMAC_SHA1;
?S_TSIG_HMAC_SHA1_96 -> ?T_TSIG_HMAC_SHA1_96;
?S_TSIG_HMAC_SHA224 -> ?T_TSIG_HMAC_SHA224;
?S_TSIG_HMAC_SHA256 -> ?T_TSIG_HMAC_SHA256;
?S_TSIG_HMAC_SHA256_128 -> ?T_TSIG_HMAC_SHA256_128;
?S_TSIG_HMAC_SHA384 -> ?T_TSIG_HMAC_SHA384;
?S_TSIG_HMAC_SHA384_192 -> ?T_TSIG_HMAC_SHA384_192;
?S_TSIG_HMAC_SHA512 -> ?T_TSIG_HMAC_SHA512;
?S_TSIG_HMAC_SHA512_256 -> ?T_TSIG_HMAC_SHA512_256;
Alg when is_list(Alg) -> Alg % raw unknown algname
end.
48 changes: 48 additions & 0 deletions lib/kernel/src/inet_dns.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@
-define(NOTAUTH, 9). %% server not authoritative for zone (DDNS)
-define(NOTZONE, 10). %% name not contained in zone (DDNS)
-define(BADVERS, 16). %% bad version EDNS pseudo-rr RFC6891: 6.1.3
-define(BADSIG, 16). %% TSIG Signature Failure (TSIG)
-define(BADKEY, 17). %% Key not recognized (TSIG)
-define(BADTIME, 18). %% Signature out of time window (TSIG)
-define(BADTRUNC, 22). %% Bad Truncation (TSIG)

%%
%% Type values for resources and queries
Expand Down Expand Up @@ -80,6 +84,7 @@
-define(T_UID, 101). %% user ID
-define(T_GID, 102). %% group ID
-define(T_UNSPEC, 103). %% Unspecified format (binary data)
-define(T_TSIG, 250). %% transaction signature
-define(T_IXFR, 251). %% incremental zone transfer
-define(T_AXFR, 252). %% zone transfer
-define(T_MAILB, 253). %% transfer mailbox records
Expand Down Expand Up @@ -124,6 +129,7 @@
-define(S_UID, uid). %% user ID
-define(S_GID, gid). %% group ID
-define(S_UNSPEC, unspec). %% Unspecified format (binary data)
-define(S_TSIG, tsig). %% transaction signature
-define(S_IXFR, ixfr). %% incremental zone transfer
-define(S_AXFR, axfr). %% zone transfer
-define(S_MAILB, mailb). %% transfer mailbox records
Expand All @@ -143,6 +149,33 @@
-define(C_NONE, 254). %% for DDNS (RFC2136, section 2.4)
-define(C_ANY, 255). %% wildcard match

%%
%% TSIG Algorithms and Identifiers (RFC8945, section 6)
%%
-define(T_TSIG_HMAC_MD5, "HMAC-MD5.SIG-ALG.REG.INT").
-define(T_TSIG_GSS_TSIG, "gss-tsig").
-define(T_TSIG_HMAC_SHA1, "hmac-sha1").
-define(T_TSIG_HMAC_SHA1_96, "hmac-sha1_96").
-define(T_TSIG_HMAC_SHA224, "hmac-sha224").
-define(T_TSIG_HMAC_SHA256, "hmac-sha256").
-define(T_TSIG_HMAC_SHA256_128, "hmac-sha256-128").
-define(T_TSIG_HMAC_SHA384, "hmac-sha384").
-define(T_TSIG_HMAC_SHA384_192, "hmac-sha384-192").
-define(T_TSIG_HMAC_SHA512, "hmac-sha512").
-define(T_TSIG_HMAC_SHA512_256, "hmac-sha512-256").
% map mostly to crypto:hmac_hash_algorithm()
-define(S_TSIG_HMAC_MD5, md5).
-define(S_TSIG_GSS_TSIG, gss_tsig).
-define(S_TSIG_HMAC_SHA1, sha).
-define(S_TSIG_HMAC_SHA1_96, {sha,96}).
-define(S_TSIG_HMAC_SHA224, sha224).
-define(S_TSIG_HMAC_SHA256, sha256).
-define(S_TSIG_HMAC_SHA256_128, {sha256,128}).
-define(S_TSIG_HMAC_SHA384, sha384).
-define(S_TSIG_HMAC_SHA384_192, {sha384,192}).
-define(S_TSIG_HMAC_SHA512, sha512).
-define(S_TSIG_HMAC_SHA512_256, {sha512,256}).

%%
%% Structure for query header, the order of the fields is machine and
%% compiler dependent, in our case, the bits within a byte are assignd
Expand Down Expand Up @@ -206,6 +239,21 @@
do = false %% RFC6891(6.1.3 DO)
}).

-record(dns_rr_tsig, %% TSIG RR OPT (RFC8945), dns_rr{type=tsig}
{
domain = "", %% name of the key
type = tsig,
offset, %% position of RR in packet
%% RFC8945(4.2 TSIG Record Format)
algname,
now,
fudge,
mac,
original_id = #dns_header{}#dns_header.id,
error = #dns_header{}#dns_header.rcode,
other_data = <<>>
}).

-record(dns_query,
{
domain, %% query domain
Expand Down
Loading

0 comments on commit ffda096

Please sign in to comment.