mirror of
				https://github.com/jtesta/ssh-audit.git
				synced 2025-10-31 17:41:02 +01:00 
			
		
		
		
	 246a41d46f
			
		
	
	246a41d46f
	
	
	
		
			
			* Apply Flake8 also on `setup.py` modified: tox.ini * Fix W605 - invalid escape syntax modified: packages/setup.py modified: tox.ini * Update comment about Flake8: W504 W503 and W504 are mutual exclusive - so we have to keep one of them. modified: tox.ini * Fix F841 - variable assigned but never used modified: ssh-audit.py modified: tox.ini * Fix E741 - ambiguous variable name 'l' modified: ssh-audit.py modified: tox.ini * Fix E712 - comparison to False should be 'if cond is False' ... and not 'if conf == False'. modified: ssh-audit.py modified: tox.ini * Fix E711 - comparison to None should be 'if cond is not None' ... and not 'if cond != None'. modified: ssh-audit.py modified: tox.ini * Fix E305 - expected 2 blank lines ... after class or function definition, found 1. modified: ssh-audit.py modified: tox.ini * Fix E303 - too many blank lines modified: ssh-audit.py modified: tox.ini * Fix E303 - too many blank lines modified: ssh-audit.py modified: tox.ini * Fix E301 - expected 1 blank line, found 0 No code change necessary, probably fixed by another commit. modified: tox.ini * Fix E265 - block comment should start with '# ' There is lots of commented out code, which usually should be just deleted. I will keep it for now, as I am not yet very familiar with the code base. modified: ssh-audit.py modified: tox.ini * Fix E261 - at least two spaces before inline comment modified: ssh-audit.py modified: tox.ini * Fix E251 - unexpected spaces around keyword / parameter equals modified: packages/setup.py modified: tox.ini * Fix E231 - missing whitespace after ',' No code change necessary, probably fixed by previous commit. modified: tox.ini * Fix E226 - missing whitespace around arithmetic operator modified: ssh-audit.py modified: tox.ini * Fix W293 - blank line contains whitespace modified: ssh-audit.py modified: tox.ini * Fix E221 - multiple spaces before operator modified: ssh-audit.py modified: tox.ini * Update comment about Flake 8 E241 Lots of data is formatted as tables, so this warning is disabled for a good reason. modified: tox.ini * Fix E401 - multiple imports on one line modified: ssh-audit.py modified: tox.ini * Do not ignore Flake8 warning F401 ... as there were no errors in source code anyway. modified: tox.ini * Fix F821 - undefined name modified: ssh-audit.py modified: tox.ini * Reformat ignore section for Flake8 modified: tox.ini * Flake8 test suite modified: test/conftest.py modified: test/test_auditconf.py modified: test/test_banner.py modified: test/test_buffer.py modified: test/test_errors.py modified: test/test_output.py modified: test/test_resolve.py modified: test/test_socket.py modified: test/test_software.py modified: test/test_ssh1.py modified: test/test_ssh2.py modified: test/test_ssh_algorithm.py modified: test/test_utils.py modified: test/test_version_compare.py modified: tox.ini
		
			
				
	
	
		
			162 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			162 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #!/usr/bin/env python
 | |
| # -*- coding: utf-8 -*-
 | |
| import socket
 | |
| import errno
 | |
| import pytest
 | |
| 
 | |
| 
 | |
| # pylint: disable=attribute-defined-outside-init
 | |
| class TestErrors(object):
 | |
| 	@pytest.fixture(autouse=True)
 | |
| 	def init(self, ssh_audit):
 | |
| 		self.AuditConf = ssh_audit.AuditConf
 | |
| 		self.audit = ssh_audit.audit
 | |
| 
 | |
| 	def _conf(self):
 | |
| 		conf = self.AuditConf('localhost', 22)
 | |
| 		conf.colors = False
 | |
| 		conf.batch = True
 | |
| 		return conf
 | |
| 
 | |
| 	def _audit(self, spy, conf=None, sysexit=True):
 | |
| 		if conf is None:
 | |
| 			conf = self._conf()
 | |
| 		spy.begin()
 | |
| 		if sysexit:
 | |
| 			with pytest.raises(SystemExit):
 | |
| 				self.audit(conf)
 | |
| 		else:
 | |
| 			self.audit(conf)
 | |
| 		lines = spy.flush()
 | |
| 		return lines
 | |
| 
 | |
| 	def test_connection_unresolved(self, output_spy, virtual_socket):
 | |
| 		vsocket = virtual_socket
 | |
| 		vsocket.gsock.addrinfodata['localhost#22'] = []
 | |
| 		lines = self._audit(output_spy)
 | |
| 		assert len(lines) == 1
 | |
| 		assert 'has no DNS records' in lines[-1]
 | |
| 
 | |
| 	def test_connection_refused(self, output_spy, virtual_socket):
 | |
| 		vsocket = virtual_socket
 | |
| 		vsocket.errors['connect'] = socket.error(errno.ECONNREFUSED, 'Connection refused')
 | |
| 		lines = self._audit(output_spy)
 | |
| 		assert len(lines) == 1
 | |
| 		assert 'Connection refused' in lines[-1]
 | |
| 
 | |
| 	def test_connection_timeout(self, output_spy, virtual_socket):
 | |
| 		vsocket = virtual_socket
 | |
| 		vsocket.errors['connect'] = socket.timeout('timed out')
 | |
| 		lines = self._audit(output_spy)
 | |
| 		assert len(lines) == 1
 | |
| 		assert 'timed out' in lines[-1]
 | |
| 
 | |
| 	def test_recv_empty(self, output_spy, virtual_socket):
 | |
| 		lines = self._audit(output_spy)
 | |
| 		assert len(lines) == 1
 | |
| 		assert 'did not receive banner' in lines[-1]
 | |
| 
 | |
| 	def test_recv_timeout(self, output_spy, virtual_socket):
 | |
| 		vsocket = virtual_socket
 | |
| 		vsocket.rdata.append(socket.timeout('timed out'))
 | |
| 		lines = self._audit(output_spy)
 | |
| 		assert len(lines) == 1
 | |
| 		assert 'did not receive banner' in lines[-1]
 | |
| 		assert 'timed out' in lines[-1]
 | |
| 
 | |
| 	def test_recv_retry_till_timeout(self, output_spy, virtual_socket):
 | |
| 		vsocket = virtual_socket
 | |
| 		vsocket.rdata.append(socket.error(errno.EAGAIN, 'Resource temporarily unavailable'))
 | |
| 		vsocket.rdata.append(socket.error(errno.EWOULDBLOCK, 'Resource temporarily unavailable'))
 | |
| 		vsocket.rdata.append(socket.error(errno.EAGAIN, 'Resource temporarily unavailable'))
 | |
| 		vsocket.rdata.append(socket.timeout('timed out'))
 | |
| 		lines = self._audit(output_spy)
 | |
| 		assert len(lines) == 1
 | |
| 		assert 'did not receive banner' in lines[-1]
 | |
| 		assert 'timed out' in lines[-1]
 | |
| 
 | |
| 	def test_recv_retry_till_reset(self, output_spy, virtual_socket):
 | |
| 		vsocket = virtual_socket
 | |
| 		vsocket.rdata.append(socket.error(errno.EAGAIN, 'Resource temporarily unavailable'))
 | |
| 		vsocket.rdata.append(socket.error(errno.EWOULDBLOCK, 'Resource temporarily unavailable'))
 | |
| 		vsocket.rdata.append(socket.error(errno.EAGAIN, 'Resource temporarily unavailable'))
 | |
| 		vsocket.rdata.append(socket.error(errno.ECONNRESET, 'Connection reset by peer'))
 | |
| 		lines = self._audit(output_spy)
 | |
| 		assert len(lines) == 1
 | |
| 		assert 'did not receive banner' in lines[-1]
 | |
| 		assert 'reset by peer' in lines[-1]
 | |
| 
 | |
| 	def test_connection_closed_before_banner(self, output_spy, virtual_socket):
 | |
| 		vsocket = virtual_socket
 | |
| 		vsocket.rdata.append(socket.error(errno.ECONNRESET, 'Connection reset by peer'))
 | |
| 		lines = self._audit(output_spy)
 | |
| 		assert len(lines) == 1
 | |
| 		assert 'did not receive banner' in lines[-1]
 | |
| 		assert 'reset by peer' in lines[-1]
 | |
| 
 | |
| 	def test_connection_closed_after_header(self, output_spy, virtual_socket):
 | |
| 		vsocket = virtual_socket
 | |
| 		vsocket.rdata.append(b'header line 1\n')
 | |
| 		vsocket.rdata.append(b'\n')
 | |
| 		vsocket.rdata.append(b'header line 2\n')
 | |
| 		vsocket.rdata.append(socket.error(errno.ECONNRESET, 'Connection reset by peer'))
 | |
| 		lines = self._audit(output_spy)
 | |
| 		assert len(lines) == 3
 | |
| 		assert 'did not receive banner' in lines[-1]
 | |
| 		assert 'reset by peer' in lines[-1]
 | |
| 
 | |
| 	def test_connection_closed_after_banner(self, output_spy, virtual_socket):
 | |
| 		vsocket = virtual_socket
 | |
| 		vsocket.rdata.append(b'SSH-2.0-ssh-audit-test\r\n')
 | |
| 		vsocket.rdata.append(socket.error(54, 'Connection reset by peer'))
 | |
| 		lines = self._audit(output_spy)
 | |
| 		assert len(lines) == 2
 | |
| 		assert 'error reading packet' in lines[-1]
 | |
| 		assert 'reset by peer' in lines[-1]
 | |
| 
 | |
| 	def test_empty_data_after_banner(self, output_spy, virtual_socket):
 | |
| 		vsocket = virtual_socket
 | |
| 		vsocket.rdata.append(b'SSH-2.0-ssh-audit-test\r\n')
 | |
| 		lines = self._audit(output_spy)
 | |
| 		assert len(lines) == 2
 | |
| 		assert 'error reading packet' in lines[-1]
 | |
| 		assert 'empty' in lines[-1]
 | |
| 
 | |
| 	def test_wrong_data_after_banner(self, output_spy, virtual_socket):
 | |
| 		vsocket = virtual_socket
 | |
| 		vsocket.rdata.append(b'SSH-2.0-ssh-audit-test\r\n')
 | |
| 		vsocket.rdata.append(b'xxx\n')
 | |
| 		lines = self._audit(output_spy)
 | |
| 		assert len(lines) == 2
 | |
| 		assert 'error reading packet' in lines[-1]
 | |
| 		assert 'xxx' in lines[-1]
 | |
| 
 | |
| 	def test_non_ascii_banner(self, output_spy, virtual_socket):
 | |
| 		vsocket = virtual_socket
 | |
| 		vsocket.rdata.append(b'SSH-2.0-ssh-audit-test\xc3\xbc\r\n')
 | |
| 		lines = self._audit(output_spy)
 | |
| 		assert len(lines) == 3
 | |
| 		assert 'error reading packet' in lines[-1]
 | |
| 		assert 'ASCII' in lines[-2]
 | |
| 		assert lines[-3].endswith('SSH-2.0-ssh-audit-test?')
 | |
| 
 | |
| 	def test_nonutf8_data_after_banner(self, output_spy, virtual_socket):
 | |
| 		vsocket = virtual_socket
 | |
| 		vsocket.rdata.append(b'SSH-2.0-ssh-audit-test\r\n')
 | |
| 		vsocket.rdata.append(b'\x81\xff\n')
 | |
| 		lines = self._audit(output_spy)
 | |
| 		assert len(lines) == 2
 | |
| 		assert 'error reading packet' in lines[-1]
 | |
| 		assert '\\x81\\xff' in lines[-1]
 | |
| 
 | |
| 	def test_protocol_mismatch_by_conf(self, output_spy, virtual_socket):
 | |
| 		vsocket = virtual_socket
 | |
| 		vsocket.rdata.append(b'SSH-1.3-ssh-audit-test\r\n')
 | |
| 		vsocket.rdata.append(b'Protocol major versions differ.\n')
 | |
| 		conf = self._conf()
 | |
| 		conf.ssh1, conf.ssh2 = True, False
 | |
| 		lines = self._audit(output_spy, conf)
 | |
| 		assert len(lines) == 3
 | |
| 		assert 'error reading packet' in lines[-1]
 | |
| 		assert 'major versions differ' in lines[-1]
 |