Skip to content

Commit 9c640bd

Browse files
committed
Handle TCP Requester #recv_reply incomplete data
1 parent 96dc3d1 commit 9c640bd

File tree

2 files changed

+65
-3
lines changed

2 files changed

+65
-3
lines changed

lib/resolv.rb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -720,7 +720,8 @@ def request(sender, tout)
720720
begin
721721
reply, from = recv_reply(select_result[0])
722722
rescue Errno::ECONNREFUSED, # GNU/Linux, FreeBSD
723-
Errno::ECONNRESET # Windows
723+
Errno::ECONNRESET, # Windows
724+
EOFError
724725
# No name server running on the server?
725726
# Don't wait anymore.
726727
raise ResolvTimeout
@@ -930,10 +931,10 @@ def initialize(host, port=Port)
930931

931932
def recv_reply(readable_socks)
932933
len_data = readable_socks[0].read(2)
933-
raise Errno::ECONNRESET if len_data.nil?
934+
raise EOFError if len_data.nil? || len_data.bytesize != 2
934935
len = len_data.unpack('n')[0]
935936
reply = @socks[0].read(len)
936-
raise Errno::ECONNRESET if reply.nil?
937+
raise EOFError if reply.nil? || reply.bytesize != len
937938
return reply, nil
938939
end
939940

test/resolv/test_dns.rb

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -881,4 +881,65 @@ def test_tcp_connection_closed_after_length
881881
client_thread.join
882882
end
883883
end
884+
885+
def test_tcp_connection_closed_with_partial_length_prefix
886+
with_tcp('127.0.0.1', 0) do |t|
887+
_, server_port, _, server_address = t.addr
888+
889+
server_thread = Thread.new do
890+
ct = t.accept
891+
ct.recv(512)
892+
ct.write "A" # 1 byte
893+
ct.close
894+
end
895+
896+
client_thread = Thread.new do
897+
requester = Resolv::DNS::Requester::TCP.new(server_address, server_port)
898+
begin
899+
msg = Resolv::DNS::Message.new
900+
msg.add_question('example.org', Resolv::DNS::Resource::IN::A)
901+
sender = requester.sender(msg, msg)
902+
assert_raise(Resolv::ResolvTimeout) do
903+
requester.request(sender, 2)
904+
end
905+
ensure
906+
requester.close
907+
end
908+
end
909+
910+
server_thread.join
911+
client_thread.join
912+
end
913+
end
914+
915+
def test_tcp_connection_closed_with_partial_message_body
916+
with_tcp('127.0.0.1', 0) do |t|
917+
_, server_port, _, server_address = t.addr
918+
919+
server_thread = Thread.new do
920+
ct = t.accept
921+
ct.recv(512)
922+
ct.write([10].pack('n')) # length 10
923+
ct.write "12345" # 5 bytes (partial)
924+
ct.close
925+
end
926+
927+
client_thread = Thread.new do
928+
requester = Resolv::DNS::Requester::TCP.new(server_address, server_port)
929+
begin
930+
msg = Resolv::DNS::Message.new
931+
msg.add_question('example.org', Resolv::DNS::Resource::IN::A)
932+
sender = requester.sender(msg, msg)
933+
assert_raise(Resolv::ResolvTimeout) do
934+
requester.request(sender, 2)
935+
end
936+
ensure
937+
requester.close
938+
end
939+
end
940+
941+
server_thread.join
942+
client_thread.join
943+
end
944+
end
884945
end

0 commit comments

Comments
 (0)