def test_dynamic_switch_invalid(self): cfile = create_config(("dynamic_switch=abc", )) with pytest.raises(ConfigException): conf = Config(cfile).load() cfile = create_config(("", )) conf = Config(cfile).load() conf._dynamic_switch = "abc" with pytest.raises(ConfigException): conf.test_dynamic_switch()
def test_ipv4_and_ipv6_diff_port(self): cfile = create_config(("tls_listen=127.0.0.1:9000,:::9001", )) conf = Config(cfile).load() assert conf.tls_listen == [ ("127.0.0.1", 9000, socket.AF_INET, {}), ("::", 9001, socket.AF_INET6, {}), ]
def test_ipv6_disabled(self): cfile = create_config(("tls_listen=:::465", )) conf = Config(cfile).load() conf._tls_listen = [("::", 465, socket.AF_UNSPEC, {})] with pytest.raises(ConfigException), mock.patch( "socket.has_ipv6", False): conf.test_tls_ipv6_support()
def setUp(self): cfile = create_config(("timeout=5", "max_message_size=1024")) Config(cfile).load() controller = Controller() controller.start() self.host, self.port = controller.sock.getsockname() self.addCleanup(controller.stop)
async def test_mode_and_delay_directive(event_loop, unused_tcp_port): cfile = create_config( ("listen=:{} delay=5 mode=bounce".format(unused_tcp_port),) ) conf = Config(cfile).load() sock = _socket("127.0.0.1", unused_tcp_port, socket.AF_INET) controller = Controller(sock) controller.start() conf.flags_from_listener("127.0.0.1", unused_tcp_port) host, port = sock.getsockname() with SMTP(host, port) as client: msg = [ "From: [email protected]", "To: [email protected]", "Subject: Test", "X-Blackhole-Mode: accept", "X-Blackhole-Delay: 30", "", "Testing 1, 2, 3", ] msg = "\n".join(msg) start = time.time() code, resp = client.data(msg.encode("utf-8")) stop = time.time() assert code in [450, 451, 452, 458, 521, 550, 551, 552, 553, 571] assert round(stop - start) in (4, 5, 6) controller.stop()
def test_mode_and_delay_range_flag(self): cfile = create_config(("listen=:25 delay=15-20 mode=bounce", )) conf = Config(cfile).load() assert conf.listen == [("", 25, socket.AF_INET, { "delay": ("15", "20"), "mode": "bounce" })]
def test_create_server_ipv4_bind_works(mock_sock): cfile = create_config(("listen=127.0.0.1:9000",)) Config(cfile).load() _server = server("127.0.0.1", 9000, socket.AF_INET) assert mock_sock.called is True assert mock_sock.call_count is 1 _server["sock"].close()
def start_servers(): """Create each server listener and bind to the socket.""" config = Config() logger.debug('Starting...') create_server() if config.tls_port and config.tls_cert and config.tls_key: create_server(use_tls=True)
def run(): """Create the asyncio loop and start the server.""" args = parse_cmd_args(sys.argv[1:]) configure_logs(args) logger = logging.getLogger('blackhole') if args.test: config_test(args) try: config = Config(args.config_file).load().test() except ConfigException as err: logger.fatal(err) raise SystemExit(os.EX_USAGE) if args.background and not config.pidfile: logger.fatal('Cannot run in the background without a pidfile.') raise SystemExit(os.EX_USAGE) loop = asyncio.get_event_loop() loop.add_signal_handler(signal.SIGINT, loop.stop) start_servers() setgid() setuid() if args.background: try: Daemon(config.pidfile).daemonize() except DaemonException as err: stop_servers() logger.fatal(err) raise SystemExit(os.EX_USAGE) try: loop.run_forever() except KeyboardInterrupt: pass stop_servers() raise SystemExit(os.EX_OK)
def test_pidfile_with_permission(self): cfile = create_config(("pidfile=/tmp/path.pid", )) conf = Config(cfile).load() with mock.patch("os.path.exists", return_value=True), mock.patch("os.access", return_value=True): conf.test_pidfile()
def test_start_servers(mock_bind): cfile = create_config(('port=9000', )) Config(cfile).load() start_servers() assert len(blackhole.control._servers) is 1 assert mock_bind.called is True assert mock_bind.call_count is 1
def test_create_server_bind_works(mock_sock): assert len(blackhole.control._servers) is 0 cfile = create_config(('port=9000', )) Config(cfile).load() create_server() assert len(blackhole.control._servers) is 1 assert mock_sock.called is True assert mock_sock.call_count is 1
def test_setuid_no_perms(): cfile = create_config(("user=testuser",)) with mock.patch( "pwd.getpwnam", side_effect=PermissionError ), pytest.raises(SystemExit) as err: Config(cfile).load() setuid() assert err.value.code == 77
def test_setgid_no_perms(): cfile = create_config(("group=testgroup",)) with mock.patch( "grp.getgrnam", side_effect=PermissionError ), pytest.raises(SystemExit) as exc: Config(cfile).load() setgid() assert exc.value.code == 77
def test_load(): cfile = create_config(( "#not=thisline", "listen=10.0.0.1:1025", "mode=bounce #default accept", )) conf = Config(cfile).load() assert conf.listen == [("10.0.0.1", 1025, socket.AF_INET, {})] assert conf.tls_listen == [] cfile = create_config(( "#not=thisline", "listen=10.0.0.1:1025", """this won't be added""", "mode=bounce #default accept", )) with pytest.raises(ConfigException): Config(cfile).load()
def test_create_server_ipv6_bind_works(): cfile = create_config(("listen=:::9000",)) Config(cfile).load() with mock.patch("socket.socket.bind") as mock_sock: _server = server("::", 9000, socket.AF_INET6) _server["sock"].close() assert mock_sock.called is True assert mock_sock.call_count is 1
def test_setuid_invalid_user(): cfile = create_config(("user=testuser",)) with mock.patch("pwd.getpwnam", side_effect=KeyError), pytest.raises( SystemExit ) as exc: Config(cfile).load() setuid() assert exc.value.code == 64
def test_setuid(): cfile = create_config(("user=abc",)) with mock.patch("pwd.getpwnam") as mock_getpwnam, mock.patch( "os.setuid" ) as mock_setuid: Config(cfile).load() setuid() assert mock_getpwnam.called is True assert mock_setuid.called is True
def test_setgid(): cfile = create_config(("group=abc",)) with mock.patch("grp.getgrnam") as mock_getgrnam, mock.patch( "os.setgid" ) as mock_setgid: Config(cfile).load() setgid() assert mock_getgrnam.called is True assert mock_setgid.called is True
def test_create_server_ipv6_tls_bind_fails(): cfile = create_config(("tls_listen=:::9000",)) Config(cfile).load() with mock.patch( "socket.socket.bind", side_effect=OSError ) as mock_sock, pytest.raises(BlackholeRuntimeException): server("::", 9000, socket.AF_INET6) assert mock_sock.called is True assert mock_sock.call_count is 1
def test_default(): with mock.patch("getpass.getuser") as mock_getuser, mock.patch( "grp.getgrgid") as mock_getgrgid: conf = Config() assert conf.config_file is None assert mock_getuser.called is True assert mock_getuser.call_count is 1 assert mock_getgrgid.called is True assert mock_getgrgid.call_count is 1
def test_tls_under_1024_no_perms(self): cfile = create_config(("tls_listen=127.0.0.1:1023", )) conf = Config(cfile).load() with mock.patch("os.getuid", return_value=9000) as mock_getuid, pytest.raises( ConfigException): conf.test_tls_port() assert mock_getuid.called is True assert mock_getuid.call_count is 1
def test_tls_over_1023_available(self): cfile = create_config(("tls_listen=127.0.0.1:1024", )) conf = Config(cfile).load() with mock.patch("os.getuid", return_value=9000) as mock_getuid, mock.patch( "socket.socket.bind", return_value=True): conf.test_tls_port() assert mock_getuid.called is True assert mock_getuid.call_count is 1
def test_port_no_certkey(self): settings = ("tls_listen=127.0.0.1:123", ) cfile = create_config(settings) conf = Config(cfile).load() with pytest.raises(ConfigException): conf.test_tls_settings() assert conf.tls_listen == [("127.0.0.1", 123, socket.AF_INET, {})] assert conf.tls_cert is None assert conf.tls_key is None
def test_no_access(): conf = Config() conf.config_file = "/fake/file.conf" with mock.patch("os.access", return_value=False) as mock_os_access, pytest.raises( ConfigException): conf.load() assert mock_os_access.called is True assert mock_os_access.call_count is 1
def test_start_servers_tls(_, __): tls_cert = create_file('cert.cert') tls_key = create_file('key.key') cfile = create_config( ('port=25', 'tls_port=9000', 'tls_cert={}'.format(tls_cert), 'tls_key={}'.format(tls_key))) Config(cfile).load() start_servers() assert len(blackhole.control._servers) is 2
def test_initiation(): cfile = create_config(("",)) with mock.patch("os.access", return_value=False), mock.patch( "socket.getfqdn", return_value="a.blackhole.io" ): conf = Config(cfile) conf.load() smtp = Smtp([]) assert smtp.fqdn == "a.blackhole.io"
def test_port_cert_no_key(self): cert = create_file("crt.crt") settings = ("tls_listen=127.0.0.1:123", "tls_cert={}".format(cert)) cfile = create_config(settings) conf = Config(cfile).load() with pytest.raises(ConfigException): conf.test_tls_settings() assert conf.tls_listen == [("127.0.0.1", 123, socket.AF_INET, {})] assert conf.tls_cert == cert assert conf.tls_key is None
def test_port_key_no_cert(self): key = create_file("key.key") settings = ("tls_listen=127.0.0.1:123", "tls_key={}".format(key)) cfile = create_config(settings) conf = Config(cfile).load() with pytest.raises(ConfigException): conf.test_tls_settings() assert conf.tls_listen == [("127.0.0.1", 123, socket.AF_INET, {})] assert conf.tls_cert is None assert conf.tls_key == key
def test_key_no_port_cert(self): key = create_file("key.key") settings = ("tls_key={}".format(key), ) cfile = create_config(settings) conf = Config(cfile).load() with pytest.raises(ConfigException): conf.test_tls_settings() assert conf.tls_listen == [] assert conf.tls_cert is None assert conf.tls_key == key