mirror of
https://github.com/inspec/inspec
synced 2024-12-23 03:23:27 +00:00
3e2450e703
* Add support to use bash in host resource Netcat's presence is widely regarded as a security issue, and thus not always available. This solution first tries to use bash builtins and timeout (from coreutils), so is less likely to require installing additional packages. * Darwin UDP support in host resource * Host: use netcat first if available Signed-off-by: João Vale <jpvale@gmail.com>
364 lines
14 KiB
Ruby
364 lines
14 KiB
Ruby
# encoding: utf-8
|
|
# author: Christoph Hartmann
|
|
# author: Dominik Richter
|
|
|
|
require 'helper'
|
|
require 'inspec/resource'
|
|
|
|
describe 'Inspec::Resources::Host' do
|
|
|
|
it 'check host ping on ubuntu with dig' do
|
|
resource = MockLoader.new(:ubuntu1404).load_resource('host', 'example.com')
|
|
_(resource.resolvable?).must_equal true
|
|
_(resource.reachable?).must_equal true
|
|
_(resource.ipaddress).must_equal ["12.34.56.78", "2606:2800:220:1:248:1893:25c8:1946"]
|
|
_(resource.to_s).must_equal 'Host example.com'
|
|
end
|
|
|
|
it 'check host ping on centos 7' do
|
|
resource = MockLoader.new(:centos7).load_resource('host', 'example.com')
|
|
_(resource.resolvable?).must_equal true
|
|
_(resource.reachable?).must_equal true
|
|
_(resource.ipaddress).must_equal ["12.34.56.78", "2606:2800:220:1:248:1893:25c8:1946"]
|
|
_(resource.to_s).must_equal 'Host example.com'
|
|
end
|
|
|
|
it 'check host ping on darwin' do
|
|
resource = MockLoader.new(:osx104).load_resource('host', 'example.com')
|
|
_(resource.resolvable?).must_equal true
|
|
_(resource.reachable?).must_equal true
|
|
_(resource.ipaddress).must_equal ["12.34.56.78", "2606:2800:220:1:248:1893:25c8:1946"]
|
|
_(resource.to_s).must_equal 'Host example.com'
|
|
end
|
|
|
|
it 'check host ping on windows' do
|
|
resource = MockLoader.new(:windows).load_resource('host', 'microsoft.com')
|
|
_(resource.resolvable?).must_equal true
|
|
_(resource.reachable?).must_equal false
|
|
_(resource.ipaddress).must_equal ['134.170.185.46', '134.170.188.221']
|
|
_(resource.to_s).must_equal 'Host microsoft.com'
|
|
end
|
|
|
|
it 'check host ping on unsupported os' do
|
|
resource = MockLoader.new(:undefined).load_resource('host', 'example.com')
|
|
_(resource.resolvable?).must_equal false
|
|
_(resource.reachable?).must_equal false
|
|
_(resource.ipaddress).must_be_nil
|
|
_(resource.to_s).must_equal 'Host example.com'
|
|
end
|
|
|
|
it 'check host tcp on ubuntu' do
|
|
resource = MockLoader.new(:ubuntu1404).load_resource('host', 'example.com', port: 1234, protocol: 'tcp')
|
|
_(resource.resolvable?).must_equal true
|
|
_(resource.reachable?).must_equal true
|
|
_(resource.ipaddress).must_equal ["12.34.56.78", "2606:2800:220:1:248:1893:25c8:1946"]
|
|
_(resource.to_s).must_equal 'Host example.com port 1234 proto tcp'
|
|
end
|
|
|
|
it 'check host udp on ubuntu' do
|
|
resource = MockLoader.new(:ubuntu1404).load_resource('host', 'example.com', port: 1234, protocol: 'udp')
|
|
_(resource.resolvable?).must_equal true
|
|
_(resource.reachable?).must_equal true
|
|
_(resource.ipaddress).must_equal ["12.34.56.78", "2606:2800:220:1:248:1893:25c8:1946"]
|
|
_(resource.to_s).must_equal 'Host example.com port 1234 proto udp'
|
|
end
|
|
|
|
it 'check host tcp on centos 7' do
|
|
resource = MockLoader.new(:centos7).load_resource('host', 'example.com', port: 1234, protocol: 'tcp')
|
|
_(resource.resolvable?).must_equal true
|
|
_(resource.reachable?).must_equal true
|
|
_(resource.ipaddress).must_equal ["12.34.56.78", "2606:2800:220:1:248:1893:25c8:1946"]
|
|
_(resource.to_s).must_equal 'Host example.com port 1234 proto tcp'
|
|
end
|
|
|
|
it 'check host udp on centos 7' do
|
|
resource = MockLoader.new(:centos7).load_resource('host', 'example.com', port: 1234, protocol: 'udp')
|
|
_(resource.resolvable?).must_equal true
|
|
_(resource.reachable?).must_equal true
|
|
_(resource.ipaddress).must_equal ["12.34.56.78", "2606:2800:220:1:248:1893:25c8:1946"]
|
|
_(resource.to_s).must_equal 'Host example.com port 1234 proto udp'
|
|
end
|
|
|
|
it 'check host tcp on darwin' do
|
|
resource = MockLoader.new(:osx104).load_resource('host', 'example.com', port: 1234, protocol: 'tcp')
|
|
_(resource.resolvable?).must_equal true
|
|
_(resource.reachable?).must_equal true
|
|
_(resource.ipaddress).must_equal ["12.34.56.78", "2606:2800:220:1:248:1893:25c8:1946"]
|
|
_(resource.to_s).must_equal 'Host example.com port 1234 proto tcp'
|
|
end
|
|
|
|
it 'check host udp on darwin' do
|
|
resource = MockLoader.new(:osx104).load_resource('host', 'example.com', port: 1234, protocol: 'udp')
|
|
_(resource.resolvable?).must_equal true
|
|
_(resource.reachable?).must_equal true
|
|
_(resource.ipaddress).must_equal ["12.34.56.78", "2606:2800:220:1:248:1893:25c8:1946"]
|
|
_(resource.to_s).must_equal 'Host example.com port 1234 proto udp'
|
|
end
|
|
|
|
it 'check host tcp on windows' do
|
|
resource = MockLoader.new(:windows).load_resource('host', 'microsoft.com', port: 1234, protocol: 'tcp')
|
|
_(resource.resolvable?).must_equal true
|
|
_(resource.reachable?).must_equal true
|
|
_(resource.ipaddress).must_equal ['134.170.185.46', '134.170.188.221']
|
|
_(resource.to_s).must_equal 'Host microsoft.com port 1234 proto tcp'
|
|
end
|
|
|
|
it 'check host tcp on unsupported os' do
|
|
resource = MockLoader.new(:undefined).load_resource('host', 'example.com', port: 1234, protocol: 'tcp')
|
|
_(resource.resolvable?).must_equal false
|
|
_(resource.reachable?).must_equal false
|
|
_(resource.ipaddress).must_be_nil
|
|
_(resource.to_s).must_equal 'Host example.com port 1234 proto tcp'
|
|
end
|
|
end
|
|
|
|
describe Inspec::Resources::UnixHostProvider do
|
|
let(:provider) { Inspec::Resources::UnixHostProvider.new(inspec) }
|
|
let(:inspec) { mock('inspec-backend') }
|
|
let(:nc_command) { mock('nc-command') }
|
|
let(:ncat_command) { mock('ncat-command') }
|
|
let(:timeout_command) { mock("timeout-command") }
|
|
let(:strings_command) { mock("strings-command") }
|
|
|
|
before do
|
|
inspec.stubs(:command).with('nc').returns(nc_command)
|
|
inspec.stubs(:command).with('ncat').returns(ncat_command)
|
|
inspec.stubs(:command).with('timeout').returns(timeout_command)
|
|
inspec.stubs(:command).with('gtimeout').returns(timeout_command)
|
|
inspec.stubs(:command).with("strings `which bash` | grep -qE '/dev/(tcp|udp)/'").returns(strings_command)
|
|
end
|
|
|
|
describe '#resolve_with_dig' do
|
|
let(:v4_command) { mock('v4_command') }
|
|
let(:v6_command) { mock('v6_command') }
|
|
|
|
before do
|
|
strings_command.stubs(:exit_status).returns(0)
|
|
nc_command.stubs(:exist?).returns(false)
|
|
ncat_command.stubs(:exist?).returns(false)
|
|
end
|
|
|
|
it 'returns an array of IP addresses' do
|
|
ipv4_command_output = <<-EOL
|
|
a.cname.goes.here
|
|
another.cname.cool
|
|
12.34.56.78
|
|
EOL
|
|
ipv6_command_output = <<-EOL
|
|
a.cname.goes.here
|
|
another.cname.cool
|
|
2A03:2880:F112:83:FACE:B00C::25DE
|
|
EOL
|
|
|
|
v4_command.stubs(:stdout).returns(ipv4_command_output)
|
|
v6_command.stubs(:stdout).returns(ipv6_command_output)
|
|
inspec.stubs(:command).with('dig +short AAAA testdomain.com').returns(v6_command)
|
|
inspec.stubs(:command).with('dig +short A testdomain.com').returns(v4_command)
|
|
provider.resolve_with_dig('testdomain.com').must_equal(['12.34.56.78', '2A03:2880:F112:83:FACE:B00C::25DE'])
|
|
end
|
|
|
|
it 'returns only v4 addresses if no v6 addresses are available' do
|
|
ipv4_command_output = <<-EOL
|
|
a.cname.goes.here
|
|
another.cname.cool
|
|
12.34.56.78
|
|
EOL
|
|
ipv6_command_output = <<-EOL
|
|
a.cname.goes.here
|
|
another.cname.cool
|
|
EOL
|
|
|
|
v4_command.stubs(:stdout).returns(ipv4_command_output)
|
|
v6_command.stubs(:stdout).returns(ipv6_command_output)
|
|
inspec.stubs(:command).with('dig +short AAAA testdomain.com').returns(v6_command)
|
|
inspec.stubs(:command).with('dig +short A testdomain.com').returns(v4_command)
|
|
provider.resolve_with_dig('testdomain.com').must_equal(['12.34.56.78'])
|
|
end
|
|
|
|
it 'returns only v6 addresses if no v4 addresses are available' do
|
|
ipv4_command_output = <<-EOL
|
|
a.cname.goes.here
|
|
another.cname.cool
|
|
EOL
|
|
ipv6_command_output = <<-EOL
|
|
a.cname.goes.here
|
|
another.cname.cool
|
|
2A03:2880:F112:83:FACE:B00C::25DE
|
|
EOL
|
|
|
|
v4_command.stubs(:stdout).returns(ipv4_command_output)
|
|
v6_command.stubs(:stdout).returns(ipv6_command_output)
|
|
inspec.stubs(:command).with('dig +short AAAA testdomain.com').returns(v6_command)
|
|
inspec.stubs(:command).with('dig +short A testdomain.com').returns(v4_command)
|
|
provider.resolve_with_dig('testdomain.com').must_equal(['2A03:2880:F112:83:FACE:B00C::25DE'])
|
|
end
|
|
|
|
it 'returns nil if no addresses are available' do
|
|
ipv4_command_output = <<-EOL
|
|
a.cname.goes.here
|
|
another.cname.cool
|
|
EOL
|
|
ipv6_command_output = <<-EOL
|
|
a.cname.goes.here
|
|
another.cname.cool
|
|
EOL
|
|
|
|
v4_command.stubs(:stdout).returns(ipv4_command_output)
|
|
v6_command.stubs(:stdout).returns(ipv6_command_output)
|
|
inspec.stubs(:command).with('dig +short AAAA testdomain.com').returns(v6_command)
|
|
inspec.stubs(:command).with('dig +short A testdomain.com').returns(v4_command)
|
|
provider.resolve_with_dig('testdomain.com').must_be_nil
|
|
end
|
|
end
|
|
|
|
describe '#resolve_with_getent' do
|
|
before do
|
|
strings_command.stubs(:exit_status).returns(0)
|
|
nc_command.stubs(:exist?).returns(false)
|
|
ncat_command.stubs(:exist?).returns(false)
|
|
end
|
|
|
|
it 'returns an array of IP addresses when successful' do
|
|
command_output = "123.123.123.123 STREAM testdomain.com\n2607:f8b0:4004:805::200e STREAM\n"
|
|
command = mock('getent_command')
|
|
command.stubs(:stdout).returns(command_output)
|
|
command.stubs(:exit_status).returns(0)
|
|
|
|
inspec.stubs(:command).with('getent ahosts testdomain.com').returns(command)
|
|
|
|
provider.resolve_with_getent('testdomain.com').must_equal(['123.123.123.123', '2607:f8b0:4004:805::200e'])
|
|
end
|
|
|
|
it 'returns nil if command is not successful' do
|
|
command = mock('getent_command')
|
|
command.stubs(:exit_status).returns(1)
|
|
|
|
inspec.stubs(:command).with('getent ahosts testdomain.com').returns(command)
|
|
|
|
provider.resolve_with_getent('testdomain.com').must_be_nil
|
|
end
|
|
end
|
|
|
|
|
|
describe "#ping" do
|
|
let(:command_response) { mock('response') }
|
|
|
|
before do
|
|
strings_command.stubs(:exit_status).returns(0)
|
|
ncat_command.stubs(:exist?).returns(false)
|
|
|
|
command_response.stubs(:exit_status).returns('0')
|
|
command_response.stubs(:stdout).returns('foo')
|
|
command_response.stubs(:stderr).returns('bar')
|
|
end
|
|
|
|
it "calls netcat if available" do
|
|
nc_command.stubs(:exist?).returns(true)
|
|
inspec.expects(:command).with('echo | nc -v -w 1 example.com 1234').returns(command_response)
|
|
|
|
provider.ping('example.com', '1234', 'tcp')
|
|
end
|
|
|
|
it "uses bash if netcat not available" do
|
|
nc_command.stubs(:exist?).returns(false)
|
|
inspec.expects(:command).with('timeout 1 bash -c "< /dev/tcp/example.com/1234"').returns(command_response)
|
|
|
|
provider.ping('example.com', '1234', 'tcp')
|
|
end
|
|
|
|
it "uses bash if netcat not available on Darwin" do
|
|
nc_command.stubs(:exist?).returns(false)
|
|
inspec.expects(:command).with('gtimeout 1 bash -c "< /dev/tcp/example.com/1234"').returns(command_response)
|
|
|
|
darwin_provider = Inspec::Resources::DarwinHostProvider.new(inspec)
|
|
darwin_provider.ping('example.com', '1234', 'tcp')
|
|
end
|
|
end
|
|
|
|
|
|
describe '#missing_requirements' do
|
|
describe 'bash with net redirects and no netcat' do
|
|
before do
|
|
strings_command.stubs(:exit_status).returns(0)
|
|
nc_command.stubs(:exist?).returns(false)
|
|
ncat_command.stubs(:exist?).returns(false)
|
|
end
|
|
|
|
it "returns an empty array if timeout is available" do
|
|
timeout_command.stubs(:exist?).returns(true)
|
|
provider.missing_requirements('tcp').must_equal([])
|
|
end
|
|
|
|
it "returns a missing requirement when timeout is missing" do
|
|
timeout_command.stubs(:exist?).returns(false)
|
|
provider.missing_requirements('tcp').must_equal(['timeout (part of coreutils) or netcat must be installed'])
|
|
end
|
|
end
|
|
|
|
describe 'bash without net redirects' do
|
|
before do
|
|
strings_command.stubs(:exit_status).returns(1)
|
|
end
|
|
|
|
it "returns an empty array if nc is installed but ncat is not installed" do
|
|
nc_command.stubs(:exist?).returns(true)
|
|
ncat_command.stubs(:exist?).returns(false)
|
|
provider.missing_requirements('tcp').must_equal([])
|
|
end
|
|
|
|
it "returns an empty array if nc is not installed but ncat is installed" do
|
|
nc_command.stubs(:exist?).returns(false)
|
|
ncat_command.stubs(:exist?).returns(true)
|
|
provider.missing_requirements('tcp').must_equal([])
|
|
end
|
|
|
|
it "returns an empty array if both nc and ncat are installed" do
|
|
nc_command.stubs(:exist?).returns(true)
|
|
ncat_command.stubs(:exist?).returns(true)
|
|
provider.missing_requirements('tcp').must_equal([])
|
|
end
|
|
|
|
it "returns a missing requirement when neither nc nor ncat are installed" do
|
|
nc_command.stubs(:exist?).returns(false)
|
|
ncat_command.stubs(:exist?).returns(false)
|
|
provider.missing_requirements('tcp').must_equal(['netcat must be installed'])
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#netcat_check_command' do
|
|
before do
|
|
strings_command.stubs(:exit_status).returns(1)
|
|
end
|
|
|
|
it 'returns an nc command when nc exists tcp' do
|
|
nc_command.expects(:exist?).returns(true)
|
|
ncat_command.expects(:exist?).returns(false)
|
|
provider.netcat_check_command('foo', 1234, 'tcp').must_equal 'echo | nc -v -w 1 foo 1234'
|
|
end
|
|
|
|
it 'returns an nc command when nc exists udp' do
|
|
nc_command.expects(:exist?).returns(true)
|
|
ncat_command.expects(:exist?).returns(false)
|
|
provider.netcat_check_command('foo', 1234, 'udp').must_equal 'echo | nc -v -w 1 -u foo 1234'
|
|
end
|
|
|
|
it 'returns an ncat command when nc does not exist but ncat exists tcp' do
|
|
nc_command.expects(:exist?).returns(false)
|
|
ncat_command.expects(:exist?).returns(true)
|
|
provider.netcat_check_command('foo', 1234, 'tcp').must_equal 'echo | ncat -v -w 1 foo 1234'
|
|
end
|
|
|
|
it 'returns an ncat command when nc does not exist but ncat exists udp' do
|
|
nc_command.expects(:exist?).returns(false)
|
|
ncat_command.expects(:exist?).returns(true)
|
|
provider.netcat_check_command('foo', 1234, 'udp').must_equal 'echo | ncat -v -w 1 -u foo 1234'
|
|
end
|
|
|
|
it 'returns nil if neither nc or ncat exist' do
|
|
nc_command.expects(:exist?).returns(false)
|
|
ncat_command.expects(:exist?).returns(false)
|
|
provider.netcat_check_command('foo', 1234, 'tcp').must_be_nil
|
|
end
|
|
end
|
|
end
|