diff --git a/lib/cool.io/dns_resolver.rb b/lib/cool.io/dns_resolver.rb index 4dbe959..ecf2890 100644 --- a/lib/cool.io/dns_resolver.rb +++ b/lib/cool.io/dns_resolver.rb @@ -218,6 +218,7 @@ def response_address(message) while not message.empty? type = message[2..3].unpack('n').first.to_i rdlength = message[10..11].unpack('n').first.to_i + return if message.bytesize < 12 + rdlength rdata = message[12..(12 + rdlength - 1)] message.slice!(0, 12 + rdlength) diff --git a/spec/dns_spec.rb b/spec/dns_spec.rb index 5118808..c38e3a7 100644 --- a/spec/dns_spec.rb +++ b/spec/dns_spec.rb @@ -211,6 +211,17 @@ def on_resolve_failed resolver.__send__(:on_readable) end + it "fails a response whose A record is shorter than its RDLENGTH instead of resolving a bogus address" do + truncated = dns_response_for(resolver, address: "1.2.3.4")[0...-4] + allow(resolver.instance_variable_get(:@socket)).to receive(:recvfrom_nonblock).and_return([truncated, sender]) + + expect(resolver).to_not receive(:on_success) + expect(resolver).to receive(:on_failure) + expect(resolver).to receive(:detach) + + resolver.__send__(:on_readable) + end + it "ignores a spoofed response instead of resolving or failing it" do forged = dns_response_for(resolver, address: "6.6.6.6") allow(resolver.instance_variable_get(:@socket)).to receive(:recvfrom_nonblock)