diff options
author | denpamusic <denpa@netfleet.space> | 2019-09-15 23:15:44 +0300 |
---|---|---|
committer | denpamusic <denpa@netfleet.space> | 2019-09-15 23:15:44 +0300 |
commit | e4e8e675b610b49975c8b90d1d207f6f56ac6f93 (patch) | |
tree | 8fe355be19edbad9347a5155e1b0b60f86db4e2b /test/functional | |
parent | fba84f7f415307fdc3df3efd60ec8b910e888ef5 (diff) | |
download | rspamd-e4e8e675b610b49975c8b90d1d207f6f56ac6f93.tar.gz rspamd-e4e8e675b610b49975c8b90d1d207f6f56ac6f93.zip |
[Feature] Add p0f scanner
Diffstat (limited to 'test/functional')
-rw-r--r-- | test/functional/cases/161_p0f.robot | 88 | ||||
-rw-r--r-- | test/functional/configs/p0f.conf | 11 | ||||
-rw-r--r-- | test/functional/lib/vars.py | 1 | ||||
-rwxr-xr-x | test/functional/util/dummy_p0f.py | 98 |
4 files changed, 198 insertions, 0 deletions
diff --git a/test/functional/cases/161_p0f.robot b/test/functional/cases/161_p0f.robot new file mode 100644 index 000000000..9acbf7b2d --- /dev/null +++ b/test/functional/cases/161_p0f.robot @@ -0,0 +1,88 @@ +*** Settings *** +Suite Setup p0f Setup +Suite Teardown p0f Teardown +Library Process +Library ${TESTDIR}/lib/rspamd.py +Resource ${TESTDIR}/lib/rspamd.robot +Variables ${TESTDIR}/lib/vars.py + +*** Variables *** +${CONFIG} ${TESTDIR}/configs/plugins.conf +${MESSAGE} ${TESTDIR}/messages/spam_message.eml +${MESSAGE2} ${TESTDIR}/messages/freemail.eml +${REDIS_SCOPE} Suite +${RSPAMD_SCOPE} Suite +${URL_TLD} ${TESTDIR}/../lua/unit/test_tld.dat + +*** Test Cases *** +p0f MISS + Run Dummy p0f + ${result} = Scan Message With Rspamc ${MESSAGE} --ip 1.1.1.1 + Check Rspamc ${result} P0F + Check Rspamc ${result} WINDOWS inverse=1 + Check Rspamc ${result} P0F_FAIL inverse=1 + Shutdown p0f + +p0f HIT + Run Dummy p0f ${P0F_SOCKET} windows + ${result} = Scan Message With Rspamc ${MESSAGE} --ip 1.1.1.2 + Check Rspamc ${result} P0F inverse=1 + Check Rspamc ${result} ETHER + Check Rspamc ${result} DISTGE10 + Check Rspamc ${result} WINDOWS + Shutdown p0f + +p0f NOREDIS + Shutdown Process With Children ${REDIS_PID} + Run Dummy p0f + ${result} = Scan Message With Rspamc ${MESSAGE} --ip 1.1.1.3 + Check Rspamc ${result} P0F + Check Rspamc ${result} ETHER + Check Rspamc ${result} DISTGE10 + Check Rspamc ${result} P0F_FAIL inverse=1 + Shutdown p0f + +p0f NOMATCH + Run Dummy p0f ${P0F_SOCKET} windows no_match + ${result} = Scan Message With Rspamc ${MESSAGE} --ip 1.1.1.4 + Check Rspamc ${result} P0F inverse=1 + Check Rspamc ${result} WINDOWS inverse=1 + Shutdown p0f + +p0f BADQUERY + Run Dummy p0f ${P0F_SOCKET} windows bad_query + ${result} = Scan Message With Rspamc ${MESSAGE} --ip 1.1.1.5 + Check Rspamc ${result} P0F_FAIL + Check Rspamc ${result} Malformed Query + Check Rspamc ${result} WINDOWS inverse=1 + Shutdown p0f + +p0f FAILURE + Run Dummy p0f ${P0F_SOCKET} windows fail + ${result} = Scan Message With Rspamc ${MESSAGE} --ip 1.1.1.6 + Check Rspamc ${result} P0F_FAIL + Check Rspamc ${result} Malformed Response + Check Rspamc ${result} WINDOWS inverse=1 + Shutdown p0f + +*** Keywords *** +p0f Setup + ${PLUGIN_CONFIG} = Get File ${TESTDIR}/configs/p0f.conf + Set Suite Variable ${PLUGIN_CONFIG} + Generic Setup PLUGIN_CONFIG + Run Redis + +p0f Teardown + Normal Teardown + Shutdown Process With Children ${REDIS_PID} + Shutdown p0f + Terminate All Processes kill=True + +Shutdown p0f + ${p0f_pid} = Get File if exists /tmp/dummy_p0f.pid + Run Keyword if ${p0f_pid} Shutdown Process With Children ${p0f_pid} + +Run Dummy p0f + [Arguments] ${socket}=${P0F_SOCKET} ${os}=linux ${status}=ok + ${result} = Start Process ${TESTDIR}/util/dummy_p0f.py ${socket} ${os} ${status} + Wait Until Created /tmp/dummy_p0f.pid diff --git a/test/functional/configs/p0f.conf b/test/functional/configs/p0f.conf new file mode 100644 index 000000000..69303772a --- /dev/null +++ b/test/functional/configs/p0f.conf @@ -0,0 +1,11 @@ +redis { + servers = "${REDIS_ADDR}:${REDIS_PORT}"; +} +p0f { + socket = "${P0F_SOCKET}"; + patterns { + WINDOWS = '^Windows.*'; + ETHER = '^Ethernet.*'; + DISTGE10 = '^distance:[0-9]{2}$'; + } +} diff --git a/test/functional/lib/vars.py b/test/functional/lib/vars.py index 97b53b2e1..4559db205 100644 --- a/test/functional/lib/vars.py +++ b/test/functional/lib/vars.py @@ -15,6 +15,7 @@ PORT_PROXY = 56795 PORT_CLAM = 56796 PORT_FPROT = 56797 PORT_FPROT2_DUPLICATE = 56798 +P0F_SOCKET = '/tmp/p0f.sock' REDIS_ADDR = u'127.0.0.1' REDIS_PORT = 56379 NGINX_ADDR = u'127.0.0.1' diff --git a/test/functional/util/dummy_p0f.py b/test/functional/util/dummy_p0f.py new file mode 100755 index 000000000..e44844812 --- /dev/null +++ b/test/functional/util/dummy_p0f.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python + +PID = "/tmp/dummy_p0f.pid" + +import os +import sys +import struct +import socket +import dummy_killer +try: + import SocketServer as socketserver +except: + import socketserver + +class MyStreamHandler(socketserver.BaseRequestHandler): + + def handle(self): + S = { + 'bad_query' : 0x0, + 'ok' : 0x10, + 'no_match' : 0x20 + } + + OS = { + 'windows' : ('Windows', '7 or 8'), + 'linux' : ('Linux', '3.11 and newer') + } + + self.data = self.request.recv(21).strip() + + if self.server.p0f_status == 'fail': + response = 0 + else: + response = struct.pack( + "IbIIIIIIIhbb32s32s32s32s32s32s", + 0x50304602, # magic + S[self.server.p0f_status], # status + 1568493408, # first_seen + 1568493408, # last_seen + 1, # total_conn + 1, # uptime_min + 4, # up_mod_days + 1568493408, # last_nat + 1568493408, # last_chg + 10, # distance + 0, # bad_sw + 0, # os_match_q + OS[self.server.p0f_os][0], # os_name + OS[self.server.p0f_os][1], # os_flavor + '', # http_name + '', # http_flavor + 'Ethernet or modem', # link_type + '' # language + ) + + self.request.sendall(response) + self.request.close() + +def cleanup(SOCK): + if os.path.exists(SOCK): + try: + os.unlink(SOCK) + except OSError: + logging.warning("Could not unlink socket %s", SOCK) + +if __name__ == "__main__": + SOCK = '/tmp/p0f.sock' + p0f_status = 'ok' + p0f_os = 'linux' + + alen = len(sys.argv) + if alen > 1: + SOCK = sys.argv[1] + if alen >= 4: + p0f_os = sys.argv[2] + p0f_status = sys.argv[3] + elif alen >= 3: + p0f_os = sys.argv[2] + + cleanup(SOCK) + + server = socketserver.UnixStreamServer(SOCK, MyStreamHandler, bind_and_activate=False) + server.allow_reuse_address = True + server.p0f_status = p0f_status + server.p0f_os = p0f_os + server.server_bind() + server.server_activate() + + dummy_killer.setup_killer(server) + dummy_killer.write_pid(PID) + + try: + server.handle_request() + except socket.error: + print "Socket closed" + + server.server_close() + cleanup(SOCK) |