diff --git a/lib/rex/socket.rb b/lib/rex/socket.rb index 28039c2..1647a52 100644 --- a/lib/rex/socket.rb +++ b/lib/rex/socket.rb @@ -942,14 +942,14 @@ def self.rex_gethostbyname(name, resolver: @@resolver) def self.rex_getaddrinfo(name, resolver: @@resolver) getaddrinfo = [] - if name =~ /^\d+$/ && name.to_i.between?(0, 0xffffffff) + if name =~ /\A\d+\Z/ && name.to_i.between?(0, 0xffffffff) getaddrinfo << Addrinfo.new( self.to_sockaddr(name.to_i, 0), ::Socket::AF_INET, ::Socket::SOCK_STREAM, ::Socket::IPPROTO_TCP ) - elsif name =~ /^0x[0-9a-fA-F]+$/ && name.to_i(16).between?(0, 0xffffffff) + elsif name =~ /\A0x[0-9a-fA-F]+\Z/ && name.to_i(16).between?(0, 0xffffffff) getaddrinfo << Addrinfo.new( self.to_sockaddr(name.to_i(16), 0), ::Socket::AF_INET, diff --git a/spec/rex/socket_spec.rb b/spec/rex/socket_spec.rb index 26915bf..d8fe98e 100644 --- a/spec/rex/socket_spec.rb +++ b/spec/rex/socket_spec.rb @@ -207,6 +207,10 @@ expect(mock_resolver).not_to receive(:send) end + after(:each) do + described_class._install_global_resolver(nil) + end + context 'when passed in a decimal hostname' do let(:hostname) { '0' } let(:response_addresses) { ['0.0.0.0'] } @@ -420,4 +424,74 @@ end end end + + describe '.rex_getaddrinfo' do + subject(:addrinfos) do + described_class.rex_getaddrinfo(hostname) + end + + context 'with a hostname' do + let(:hostname) { 'localhost' } + it 'should call .rex_resolve_hostname' do + expect(described_class).to receive(:rex_resolve_hostname).with(hostname, {resolver: nil}).and_return([ [], [] ]) + subject + end + + it 'should return IPv4 and IPv6 addresses' do + expect(described_class).to receive(:rex_resolve_hostname).and_return([ + [Dnsruby::RR::IN::A.new(address: '127.0.0.1')], + [Dnsruby::RR::IN::AAAA.new(address: '::1')] + ]) + + expect(subject).to match_array([ + have_attributes(ip_address: '127.0.0.1', afamily: ::Socket::AF_INET, socktype: ::Socket::SOCK_STREAM, protocol: ::Socket::IPPROTO_TCP), + have_attributes(ip_address: '::1', afamily: ::Socket::AF_INET6, socktype: ::Socket::SOCK_STREAM, protocol: ::Socket::IPPROTO_TCP) + ]) + end + end + + context 'with a decimal name' do + let(:hostname) { '255' } + it 'should not call .rex_resolve_hostname' do + expect(described_class).to_not receive(:rex_resolve_hostname) + subject + end + + it 'should return one IPv4 address' do + expect(subject).to match_array([ + have_attributes(ip_address: '0.0.0.255', afamily: ::Socket::AF_INET, socktype: ::Socket::SOCK_STREAM, protocol: ::Socket::IPPROTO_TCP), + ]) + end + end + + context 'with an invalid decimal name' do + let(:hostname) { '4294967296' } + it 'should call .rex_resolve_hostname' do + expect(described_class).to receive(:rex_resolve_hostname).with(hostname, {resolver: nil}).and_raise(::SocketError.new('getaddrinfo: Name or service not known')) + expect { subject }.to raise_error(::SocketError) + end + end + + context 'with a hexadecimal name' do + let(:hostname) { '0xff' } + it 'should not call .rex_resolve_hostname' do + expect(described_class).to_not receive(:rex_resolve_hostname) + subject + end + + it 'should return one IPv4 address' do + expect(subject).to match_array([ + have_attributes(ip_address: '0.0.0.255', afamily: ::Socket::AF_INET, socktype: ::Socket::SOCK_STREAM, protocol: ::Socket::IPPROTO_TCP), + ]) + end + end + + context 'with an invalid hexadecimal name' do + let(:hostname) { '0x100000000' } + it 'should call .rex_resolve_hostname' do + expect(described_class).to receive(:rex_resolve_hostname).with(hostname, {resolver: nil}).and_raise(::SocketError.new('getaddrinfo: Name or service not known')) + expect { subject }.to raise_error(::SocketError) + end + end + end end