Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SPF/TXT multipart handling #150

Merged
merged 17 commits into from
Mar 27, 2025
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ priv/_*.json
.eunit/
db/
_build/
_checkouts/
doc/
Mnesia.nonode@nohost/
*.DCD
Expand Down
116 changes: 116 additions & 0 deletions priv/zones-test.json
Original file line number Diff line number Diff line change
Expand Up @@ -2686,6 +2686,122 @@
}
]
},
{
"name": "multipart.example",
"records": [
{
"name": "multipart.example",
"type": "SOA",
"data": {
"mname": "ns1.example.com",
"rname": "ahu.example.com",
"serial": 2000081501,
"refresh": 28800,
"retry": 7200,
"expire": 604800,
"minimum": 86400
},
"ttl": 120
},
{
"name": "multipart.example",
"type": "NS",
"ttl": 120,
"data": {
"dname": "ns1.example.com"
}
},
{
"name": "multipart.example",
"type": "NS",
"ttl": 120,
"data": {
"dname": "ns2.example.com"
}
},
{
"name": "txt1a.multipart.example",
"type": "TXT",
"ttl": 120,
"data": {
"txt": "string one"
}
},
{
"name": "txt1b.multipart.example",
"type": "TXT",
"ttl": 120,
"data": {
"txt": "string one",
"txts": [
"string one"
]
}
},
{
"name": "txt2a.multipart.example",
"type": "TXT",
"ttl": 120,
"data": {
"txt": "\"string one\" \"string two\""
}
},
{
"name": "txt2b.multipart.example",
"type": "TXT",
"ttl": 120,
"data": {
"txt": "\"string one\" \"string two\"",
"txts": [
"string one",
"string two"
]
}
},
{
"name": "txt2c.multipart.example",
"type": "TXT",
"ttl": 120,
"data": {
"txts": [
"string one",
"string two"
]
}
},
{
"name": "txt2d.multipart.example",
"type": "TXT",
"ttl": 120,
"data": {
"txt": "\"string a\" \"string b\"",
"txts": [
"string c",
"string d"
]
}
},
{
"name": "spf1a.multipart.example",
"type": "SPF",
"ttl": 120,
"data": {
"spf": "v=spf1 include:_spf.spf.example.com ~all"
}
},
{
"name": "spf1b.multipart.example",
"type": "SPF",
"ttl": 120,
"data": {
"spf": "v=spf1 include:_spf.spf.example.com ~all",
"txts": [
"v=spf1 include:_spf.txts.example.com ~all"
]
}
}
]
},
{
"name": "test.com",
"records": [
Expand Down
2 changes: 1 addition & 1 deletion rebar.config
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
{lager, "3.9.2"},
recon,
folsom,
{dns_erlang, "2.0.0"},
{dns_erlang, "3.0.2"},
iso8601,
{nodefinder, "2.0.7"},
{meck, "1.0.0"}
Expand Down
6 changes: 3 additions & 3 deletions rebar.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{"1.2.0",
[{<<"base32">>,{pkg,<<"base32">>,<<"0.1.0">>},1},
{<<"bear">>,{pkg,<<"bear">>,<<"1.0.0">>},1},
{<<"dns_erlang">>,{pkg,<<"dns_erlang">>,<<"2.0.0">>},0},
{<<"dns_erlang">>,{pkg,<<"dns_erlang">>,<<"3.0.2">>},0},
{<<"folsom">>,{pkg,<<"folsom">>,<<"1.0.0">>},0},
{<<"goldrush">>,{pkg,<<"goldrush">>,<<"0.1.9">>},1},
{<<"iso8601">>,{pkg,<<"iso8601">>,<<"1.3.4">>},0},
Expand All @@ -13,7 +13,7 @@
{pkg_hash,[
{<<"base32">>, <<"044F6DC95709727CA2176F3E97A41DDAA76B5BC690D3536908618C0CB32616A2">>},
{<<"bear">>, <<"430419C1126B477686CDE843E88BA0F2C7DC5CDF0881C677500074F704339A99">>},
{<<"dns_erlang">>, <<"2C6E08842101AC04FFD634ABF7E2761A92F010ECD824AD950E9B5478F25D6F37">>},
{<<"dns_erlang">>, <<"BC29B2C30F0ED1195035FEBF38F8137F999FCA91C03A62C1EDF15D346B8D5A2F">>},
{<<"folsom">>, <<"50ECC998D2149939F1D5E0AA3E32788F8ED16A58E390D81B5C0BE4CC4EF25589">>},
{<<"goldrush">>, <<"F06E5D5F1277DA5C413E84D5A2924174182FB108DABB39D5EC548B27424CD106">>},
{<<"iso8601">>, <<"7B1F095F86F6CF65E1E5A77872E8E8BF69BD58D4C3A415B3F77D9CC9423ECBB9">>},
Expand All @@ -24,7 +24,7 @@
{pkg_hash_ext,[
{<<"base32">>, <<"10A73951D857D8CB1ECEEA8EB96C6941F6A76E105947AD09C2B73977DEE07638">>},
{<<"bear">>, <<"157B67901ADF84FF0DA6EAE035CA1292A0AC18AA55148154D8C582B2C68959DB">>},
{<<"dns_erlang">>, <<"3C68246BC17C375FDB187E2D75951A83850257FCABC47E52E447EBAD5F34B690">>},
{<<"dns_erlang">>, <<"306A2F1AB47E8EDBE3630C77DB79C8EE22AED35E8CCA4C1BA6F1E977CFCB092F">>},
{<<"folsom">>, <<"DD6AB97278E94F9E4CFC43E188224A7B8C7EAEC0DD2E935007005177F3EEBB0E">>},
{<<"goldrush">>, <<"99CB4128CFFCB3227581E5D4D803D5413FA643F4EB96523F77D9E6937D994CEB">>},
{<<"iso8601">>, <<"A334469C07F1C219326BC891A95F5EEC8EB12DD8071A3FFF56A7843CB20FAE34">>},
Expand Down
2 changes: 1 addition & 1 deletion src/erldns_resolver.erl
Original file line number Diff line number Diff line change
Expand Up @@ -780,7 +780,7 @@ additional_processing(Message, _Host, _Zone, _Names, Records) ->
Message#dns_message{additional = Message#dns_message.additional ++ Records}.

%% Given a list of answers find the names that require additional processing.
-spec requires_additional_processing(Records :: [dns:rr()], RecordsRequiringAdditionalProcessing :: [dns:rr()]) -> [dns:rr()].
-spec requires_additional_processing(Records :: [dns:rr()], RequiresAdditional :: [dns:dname()]) -> [dns:dname()].
requires_additional_processing([], RequiresAdditional) ->
RequiresAdditional;
requires_additional_processing([Answer | Rest], RequiresAdditional) ->
Expand Down
9 changes: 4 additions & 5 deletions src/erldns_worker_process.erl
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,10 @@ send_tcp_message(Socket, EncodedMessage) ->
max_payload_size(Message) ->
case Message#dns_message.additional of
[Opt | _] when is_record(Opt, dns_optrr) ->
case Opt#dns_optrr.udp_payload_size of
[] ->
?MAX_PACKET_SIZE;
_ ->
Opt#dns_optrr.udp_payload_size
Size = Opt#dns_optrr.udp_payload_size,
case Size < ?MAX_PACKET_SIZE of
true -> Size;
false -> ?MAX_PACKET_SIZE
end;
_ ->
?MAX_PACKET_SIZE
Expand Down
62 changes: 41 additions & 21 deletions src/erldns_zone_parser.erl
Original file line number Diff line number Diff line change
Expand Up @@ -509,23 +509,29 @@ json_record_to_erlang([Name, <<"RP">>, Ttl, Data, _Context]) ->
ttl = Ttl
};
json_record_to_erlang([Name, Type = <<"TXT">>, Ttl, Data, _Context]) when is_map(Data) ->
%% This function call may crash. Handle it as a bad record.
try erldns_txt:parse(maps:get(<<"txt">>, Data)) of
ParsedText ->
#dns_rr{
name = Name,
type = ?DNS_TYPE_TXT,
data = #dns_rrdata_txt{txt = lists:flatten(ParsedText)},
ttl = Ttl
}
catch
Exception:Reason ->
erldns_events:notify({?MODULE, error, {Name, Type, Data, Exception, Reason}}),
{}
end;
Txts =
case maps:is_key(<<"txts">>, Data) of
true -> maps:get(<<"txts">>, Data);
false -> maps:get(<<"txt">>, Data)
end,
json_record_to_erlang([Name, Type, Ttl, Data, _Context, Txts]);
json_record_to_erlang([Name, Type = <<"TXT">>, Ttl, Data, _Context]) ->
Txts =
case erldns_config:keyget(<<"txts">>, Data) of
Value when is_list(Value) -> Value;
_ -> erldns_config:keyget(<<"txt">>, Data)
end,
json_record_to_erlang([Name, Type, Ttl, Data, _Context, Txts]);
json_record_to_erlang([Name, <<"TXT">>, Ttl, _Data, _Context, Value]) when is_list(Value) ->
#dns_rr{
name = Name,
type = ?DNS_TYPE_TXT,
data = #dns_rrdata_txt{txt = Value},
ttl = Ttl
};
json_record_to_erlang([Name, Type = <<"TXT">>, Ttl, Data, _Context, Value]) ->
%% This function call may crash. Handle it as a bad record.
try erldns_txt:parse(erldns_config:keyget(<<"txt">>, Data)) of
try erldns_txt:parse(Value) of
ParsedText ->
#dns_rr{
name = Name,
Expand All @@ -539,17 +545,27 @@ json_record_to_erlang([Name, Type = <<"TXT">>, Ttl, Data, _Context]) ->
{}
end;
json_record_to_erlang([Name, <<"SPF">>, Ttl, Data, _Context]) when is_map(Data) ->
Txts =
case maps:is_key(<<"txts">>, Data) of
true -> maps:get(<<"txts">>, Data);
false -> [maps:get(<<"spf">>, Data)]
end,
#dns_rr{
name = Name,
type = ?DNS_TYPE_SPF,
data = #dns_rrdata_spf{spf = [maps:get(<<"spf">>, Data)]},
data = #dns_rrdata_spf{spf = Txts},
ttl = Ttl
};
json_record_to_erlang([Name, <<"SPF">>, Ttl, Data, _Context]) ->
Txts =
case erldns_config:keyget(<<"txts">>, Data) of
Value when is_list(Value) -> Value;
_ -> [erldns_config:keyget(<<"spf">>, Data)]
end,
#dns_rr{
name = Name,
type = ?DNS_TYPE_SPF,
data = #dns_rrdata_spf{spf = [erldns_config:keyget(<<"spf">>, Data)]},
data = #dns_rrdata_spf{spf = Txts},
ttl = Ttl
};
json_record_to_erlang([Name, <<"PTR">>, Ttl, Data, _Context]) when is_map(Data) ->
Expand Down Expand Up @@ -753,7 +769,8 @@ json_record_to_erlang([Name, Type = <<"DNSKEY">>, Ttl, Data, _Context]) when is_
flags = maps:get(<<"flags">>, Data),
protocol = maps:get(<<"protocol">>, Data),
alg = maps:get(<<"alg">>, Data),
public_key = PublicKey
public_key = PublicKey,
key_tag = 0
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this change originating? Is it anyhow changing the current behavior?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It comes from the new type requirements, requiring this element to be an integer. This is read when decoding, but in code it is never used during encoding as far as I could find. We can allow it to be an undefined if we update dns_erlang, but it seems to me from RFC4034 (https://datatracker.ietf.org/doc/html/rfc4034#section-3.1.6) that this is never supposed not to be an integer 🤔

},
ttl = Ttl
})
Expand All @@ -773,7 +790,8 @@ json_record_to_erlang([Name, Type = <<"DNSKEY">>, Ttl, Data, _Context]) ->
flags = erldns_config:keyget(<<"flags">>, Data),
protocol = erldns_config:keyget(<<"protocol">>, Data),
alg = erldns_config:keyget(<<"alg">>, Data),
public_key = PublicKey
public_key = PublicKey,
key_tag = 0
},
ttl = Ttl
})
Expand All @@ -793,7 +811,8 @@ json_record_to_erlang([Name, Type = <<"CDNSKEY">>, Ttl, Data, _Context]) when is
flags = maps:get(<<"flags">>, Data),
protocol = maps:get(<<"protocol">>, Data),
alg = maps:get(<<"alg">>, Data),
public_key = PublicKey
public_key = PublicKey,
key_tag = 0
},
ttl = Ttl
})
Expand All @@ -813,7 +832,8 @@ json_record_to_erlang([Name, Type = <<"CDNSKEY">>, Ttl, Data, _Context]) ->
flags = erldns_config:keyget(<<"flags">>, Data),
protocol = erldns_config:keyget(<<"protocol">>, Data),
alg = erldns_config:keyget(<<"alg">>, Data),
public_key = PublicKey
public_key = PublicKey,
key_tag = 0
},
ttl = Ttl
})
Expand Down