diff --git a/conpot/core/attack_session.py b/conpot/core/attack_session.py index b0cbdc96..adad3080 100644 --- a/conpot/core/attack_session.py +++ b/conpot/core/attack_session.py @@ -23,9 +23,16 @@ logger = logging.getLogger(__name__) -# one instance per connection +NEW_CONNECTION = "NEW_CONNECTION" +CONNECTION_LOST = "CONNECTION_LOST" +CONNECTION_CLOSED = "CONNECTION_CLOSED" +CONNECTION_FAILED = "CONNECTION_FAILED" +CONNECTION_TERMINATED = "CONNECTION_TERMINATED" +CONNECTION_QUIT = "CONNECTION_QUIT" +CONNECTION_TIMEOUT = "CONNECTION_TIMEOUT" +# one instance per connection class AttackSession(object): def __init__( self, diff --git a/conpot/protocols/IEC104/IEC104_server.py b/conpot/protocols/IEC104/IEC104_server.py index d66761ab..da45affd 100644 --- a/conpot/protocols/IEC104/IEC104_server.py +++ b/conpot/protocols/IEC104/IEC104_server.py @@ -19,6 +19,7 @@ from .frames import struct, TESTFR_act, socket, errno import logging import conpot.core as conpot_core +from conpot.core import attack_session from gevent.server import StreamServer import gevent from .errors import Timeout_t3 @@ -52,7 +53,7 @@ def handle(self, sock, address): address[1], session.id, ) - session.add_event({"type": "NEW_CONNECTION"}) + session.add_event({"type": attack_session.NEW_CONNECTION}) iec104_handler = IEC104(self.device_data_controller, sock, address, session.id) try: while True: @@ -65,7 +66,7 @@ def handle(self, sock, address): request = sock.recv(6) if not request: logger.info("IEC104 Station disconnected. (%s)", session.id) - session.add_event({"type": "CONNECTION_LOST"}) + session.add_event({"type": attack.session.CONNECTION_LOST}) iec104_handler.disconnect() break while request and len(request) < 2: @@ -122,18 +123,18 @@ def handle(self, sock, address): except gevent.Timeout: logger.warning("T1 timed out. (%s)", session.id) logger.info("IEC104 Station disconnected. (%s)", session.id) - session.add_event({"type": "CONNECTION_LOST"}) + session.add_event({"type": attack_session.CONNECTION_LOST}) iec104_handler.disconnect() break except socket.timeout: logger.debug("Socket timeout, remote: %s. (%s)", address[0], session.id) - session.add_event({"type": "CONNECTION_LOST"}) + session.add_event({"type": attack_session.CONNECTION_LOST}) except socket.error as err: if isinstance(err.args, tuple): if err.errno == errno.EPIPE: # remote peer disconnected logger.info("IEC104 Station disconnected. (%s)", session.id) - session.add_event({"type": "CONNECTION_LOST"}) + session.add_event({"type": attack_session.CONNECTION_LOST}) else: # determine and handle different error pass diff --git a/conpot/protocols/bacnet/bacnet_server.py b/conpot/protocols/bacnet/bacnet_server.py index 5ce34cc4..1d829125 100644 --- a/conpot/protocols/bacnet/bacnet_server.py +++ b/conpot/protocols/bacnet/bacnet_server.py @@ -28,6 +28,7 @@ import conpot.core as conpot_core from conpot.protocols.bacnet.bacnet_app import BACnetApp from conpot.core.protocol_wrapper import conpot_protocol +from conpot.core import attack_session from conpot.utils.networking import get_interface_ip import logging @@ -69,7 +70,7 @@ def handle(self, data, address): logger.info( "New Bacnet connection from %s:%d. (%s)", address[0], address[1], session.id ) - session.add_event({"type": "NEW_CONNECTION"}) + session.add_event({"type": attack_session.NEW_CONNECTION}) # I'm not sure if gevent DatagramServer handles issues where the # received data is over the MTU -> fragmentation if data: diff --git a/conpot/protocols/enip/enip_server.py b/conpot/protocols/enip/enip_server.py index 97d570ef..d3be4e2c 100644 --- a/conpot/protocols/enip/enip_server.py +++ b/conpot/protocols/enip/enip_server.py @@ -29,6 +29,7 @@ from cpppo.server.enip import parser from cpppo.server.enip import device from conpot.core.protocol_wrapper import conpot_protocol +from conpot.core import attack_session import conpot.core as conpot_core logger = logging.getLogger(__name__) @@ -133,7 +134,7 @@ def handle(self, conn, address, enip_process=None, delay=None, **kwds): "enip", host, port, conn.getsockname()[0], conn.getsockname()[1] ) logger.debug("ENIP server %s begins serving client %s", name, address) - session.add_event({"type": "NEW_CONNECTION"}) + session.add_event({"type": attack_session.NEW_CONNECTION}) tcp = conn.family == socket.AF_INET and conn.type == socket.SOCK_STREAM udp = conn.family == socket.AF_INET and conn.type == socket.SOCK_DGRAM @@ -332,7 +333,7 @@ def handle_tcp( cpppo.timer() - begun, delayseconds, ) - session.add_event({"type": "CONNECTION_CLOSED"}) + session.add_event({"type": attack_session.CONNECTION_CLOSED}) except: logger.error("Failed request: %s", parser.enip_format(data)) enip_process(address, data=cpppo.dotdict()) # Terminate. @@ -491,7 +492,7 @@ def handle_udp(self, conn, name, enip_process, session, **kwds): logger.debug( "Transaction complete after %7.3fs", cpppo.timer() - begun ) - session.add_event({"type": "CONNECTION_CLOSED"}) + session.add_event({"type": attack_session.CONNECTION_CLOSED}) stats["processed"] = source.sent except: # Parsing failure. Suck out some remaining input to give us some context, but don't re-raise @@ -512,7 +513,7 @@ def handle_udp(self, conn, name, enip_process, session, **kwds): where, "".join(traceback.format_exception(*sys.exc_info())), ) - session.add_event({"type": "CONNECTION_FAILED"}) + session.add_event({"type": attack_session.CONNECTION_FAILED}) def set_tags(self): typenames = { diff --git a/conpot/protocols/ftp/ftp_base_handler.py b/conpot/protocols/ftp/ftp_base_handler.py index a93268a4..ce2f39f0 100644 --- a/conpot/protocols/ftp/ftp_base_handler.py +++ b/conpot/protocols/ftp/ftp_base_handler.py @@ -19,6 +19,7 @@ import gevent import conpot.core as conpot_core from conpot.core.filesystem import FilesystemError +from conpot.core import attack_session import logging import errno import time @@ -236,7 +237,7 @@ def setup(self): self.client_address[0], self.client_address[1], self.session.id ) ) - self.session.add_event({"type": "NEW_CONNECTION"}) + self.session.add_event({"type": attack_session.NEW_CONNECTION}) # send 200 + banner -- new client has connected! self.respond(b"200 " + self.config.banner.encode()) # Is there a delay in command response? < gevent.sleep(0.5) ? @@ -292,7 +293,7 @@ def handle_cmd_channel(self): self.client_address, self.session.id ) ) - self.session.add_event({"type": "CONNECTION_LOST"}) + self.session.add_event({"type": attack_session.CONNECTION_LOST}) self.finish() return socket_read, socket_write, _ = gevent.select.select( @@ -349,7 +350,7 @@ def handle_cmd_channel(self): self.client_address, self.session.id, se ) ) - self.session.add_event({"type": "CONNECTION_LOST"}) + self.session.add_event({"type": attack_session.CONNECTION_LOST}) self.finish() def respond(self, response): diff --git a/conpot/protocols/ftp/ftp_handler.py b/conpot/protocols/ftp/ftp_handler.py index fe1ed488..c85f2e3f 100644 --- a/conpot/protocols/ftp/ftp_handler.py +++ b/conpot/protocols/ftp/ftp_handler.py @@ -12,6 +12,7 @@ import gevent from gevent import socket from conpot.core.filesystem import FilesystemError, FSOperationNotPermitted +from conpot.core import attack_session from conpot.protocols.ftp.ftp_utils import FTPPrivilegeException, get_data_from_iter logger = logging.getLogger(__name__) @@ -113,7 +114,7 @@ def do_SYST(self, arg): def do_QUIT(self, arg): self.respond(b"221 Bye.") - self.session.add_event({"type": "CONNECTION_TERMINATED"}) + self.session.add_event({"type": attack_session.CONNECTION_TERMINATED}) self.disconnect_client = True def do_SITE_HELP(self, line): @@ -878,7 +879,7 @@ def _process_command(self, cmd, *args, **kwargs): if self.invalid_login_attempt >= self.max_login_attempts: self.respond(b"421 Too many connections. Service temporarily unavailable.") self.disconnect_client = True - self.session.add_event({"type": "CONNECTION_TERMINATED"}) + self.session.add_event({"type": attack_session.CONNECTION_TERMINATED}) else: try: method = getattr(self, "do_" + cmd.replace(" ", "_")) @@ -936,7 +937,9 @@ def process_ftp_command(self): ) # TODO: what to respond here? For now just terminate the session self.disconnect_client = True - self.session.add_event({"type": "CONNECTION_TERMINATED"}) + self.session.add_event( + {"type": attack_session.CONNECTION_TERMINATED} + ) elif not (self.metrics.timeout() < self.config.timeout) and ( not self._data_channel ): @@ -945,7 +948,7 @@ def process_ftp_command(self): self.client_address, self.session.id ) ) - self.session.add_event({"type": "CONNECTION_TIMEOUT"}) + self.session.add_event({"type": attack_session.CONNECTION_TIMEOUT}) self.respond(b"421 Timeout.") self.disconnect_client = True else: diff --git a/conpot/protocols/guardian_ast/guardian_ast_server.py b/conpot/protocols/guardian_ast/guardian_ast_server.py index 296642cc..8af109f8 100644 --- a/conpot/protocols/guardian_ast/guardian_ast_server.py +++ b/conpot/protocols/guardian_ast/guardian_ast_server.py @@ -25,6 +25,7 @@ import logging import random import conpot.core as conpot_core +from conpot.core import attack_session from conpot.core.protocol_wrapper import conpot_protocol from conpot.utils.networking import str_to_bytes @@ -55,7 +56,7 @@ def handle(self, sock, addr): logger.info( "New GuardianAST connection from %s:%d. (%s)", addr[0], addr[1], session.id ) - session.add_event({"type": "NEW_CONNECTION"}) + session.add_event({"type": attack_session.NEW_CONNECTION}) current_time = datetime.datetime.utcnow() fill_start = self.fill_offset_time - datetime.timedelta(minutes=313) fill_stop = self.fill_offset_time - datetime.timedelta(minutes=303) @@ -507,7 +508,7 @@ def I20500(): logger.info( "GuardianAST client disconnected %s:%d. (%s)", addr[0], addr[1], session.id ) - session.add_event({"type": "CONNECTION_LOST"}) + session.add_event({"type": attack_session.CONNECTION_LOST}) def start(self, host, port): connection = (host, port) diff --git a/conpot/protocols/kamstrup_management/kamstrup_management_server.py b/conpot/protocols/kamstrup_management/kamstrup_management_server.py index 17cf93c3..80746ea0 100644 --- a/conpot/protocols/kamstrup_management/kamstrup_management_server.py +++ b/conpot/protocols/kamstrup_management/kamstrup_management_server.py @@ -21,6 +21,7 @@ import conpot.core as conpot_core from .command_responder import CommandResponder from conpot.core.protocol_wrapper import conpot_protocol +from conpot.core import attack_session from conpot.utils.networking import str_to_bytes logger = logging.getLogger(__name__) @@ -48,7 +49,7 @@ def handle(self, sock, address): address[1], session.id, ) - session.add_event({"type": "NEW_CONNECTION"}) + session.add_event({"type": attack_session.NEW_CONNECTION}) try: sock.send( @@ -63,7 +64,7 @@ def handle(self, sock, address): data = sock.recv(1024) if not data: logger.info("Kamstrup client disconnected. (%s)", session.id) - session.add_event({"type": "CONNECTION_LOST"}) + session.add_event({"type": attack_session.CONNECTION_LOST}) break request = data.decode() logdata = {"request": request} @@ -79,7 +80,7 @@ def handle(self, sock, address): gevent.sleep(0.25) # TODO measure delay and/or RTT if response is None: - session.add_event({"type": "CONNECTION_LOST"}) + session.add_event({"type": attack_session.CONNECTION_LOST}) break # encode data before sending reply = str_to_bytes(response) @@ -87,7 +88,7 @@ def handle(self, sock, address): except socket.timeout: logger.debug("Socket timeout, remote: %s. (%s)", address[0], session.id) - session.add_event({"type": "CONNECTION_LOST"}) + session.add_event({"type": attack_session.CONNECTION_LOST}) sock.close() diff --git a/conpot/protocols/kamstrup_meter/kamstrup_server.py b/conpot/protocols/kamstrup_meter/kamstrup_server.py index d5779641..df565eab 100644 --- a/conpot/protocols/kamstrup_meter/kamstrup_server.py +++ b/conpot/protocols/kamstrup_meter/kamstrup_server.py @@ -26,6 +26,7 @@ from .request_parser import KamstrupRequestParser from .command_responder import CommandResponder from conpot.core.protocol_wrapper import conpot_protocol +from conpot.core import attack_session logger = logging.getLogger(__name__) @@ -64,7 +65,7 @@ def handle(self, sock, address): address[1], session.id, ) - session.add_event({"type": "NEW_CONNECTION"}) + session.add_event({"type": attack_session.NEW_CONNECTION}) self.server_active = True @@ -75,7 +76,7 @@ def handle(self, sock, address): if not raw_request: logger.info("Kamstrup client disconnected. (%s)", session.id) - session.add_event({"type": "CONNECTION_LOST"}) + session.add_event({"type": attack_session.CONNECTION_LOST}) break for x in raw_request: @@ -84,7 +85,7 @@ def handle(self, sock, address): while True: request = parser.get_request() if not request: - session.add_event({"type": "CONNECTION_LOST"}) + session.add_event({"type": attack_session.CONNECTION_LOST}) break else: logdata = { @@ -112,7 +113,7 @@ def handle(self, sock, address): except socket.timeout: logger.debug("Socket timeout, remote: %s. (%s)", address[0], session.id) - session.add_event({"type": "CONNECTION_LOST"}) + session.add_event({"type": attack_session.CONNECTION_LOST}) sock.close() diff --git a/conpot/protocols/modbus/modbus_server.py b/conpot/protocols/modbus/modbus_server.py index 5400b105..93d61834 100644 --- a/conpot/protocols/modbus/modbus_server.py +++ b/conpot/protocols/modbus/modbus_server.py @@ -17,6 +17,7 @@ from conpot.core.protocol_wrapper import conpot_protocol from conpot.protocols.modbus import slave_db import conpot.core as conpot_core +from conpot.core import attack_session logger = logging.getLogger(__name__) @@ -105,7 +106,7 @@ def handle(self, sock, address): logger.info( "New Modbus connection from %s:%s. (%s)", address[0], address[1], session.id ) - session.add_event({"type": "NEW_CONNECTION"}) + session.add_event({"type": attack_session.NEW_CONNECTION}) try: while True: @@ -121,17 +122,17 @@ def handle(self, sock, address): if not request: logger.info("Modbus client disconnected. (%s)", session.id) - session.add_event({"type": "CONNECTION_LOST"}) + session.add_event({"type": attack_session.CONNECTION_LOST}) break if request.strip().lower() == "quit.": logger.info("Modbus client quit. (%s)", session.id) - session.add_event({"type": "CONNECTION_QUIT"}) + session.add_event({"type": attack_session.CONNECTION_QUIT}) break if len(request) < 7: logger.info( "Modbus client provided data {} but invalid.".format(session.id) ) - session.add_event({"type": "CONNECTION_TERMINATED"}) + session.add_event({"type": attack_session.CONNECTION_TERMINATED}) break _, _, length = struct.unpack(">HHH", request[:6]) while len(request) < (length + 6): @@ -169,7 +170,9 @@ def handle(self, sock, address): logger.info( "Modbus connection terminated with client %s.", address[0] ) - session.add_event({"type": "CONNECTION_TERMINATED"}) + session.add_event( + {"type": attack_session.CONNECTION_TERMINATED} + ) sock.shutdown(socket.SHUT_RDWR) sock.close() break @@ -179,13 +182,15 @@ def handle(self, sock, address): "Modbus client ignored due to invalid addressing." " (%s)", session.id, ) - session.add_event({"type": "CONNECTION_TERMINATED"}) + session.add_event( + {"type": attack_session.CONNECTION_TERMINATED} + ) sock.shutdown(socket.SHUT_RDWR) sock.close() break except socket.timeout: logger.debug("Socket timeout, remote: %s. (%s)", address[0], session.id) - session.add_event({"type": "CONNECTION_LOST"}) + session.add_event({"type": attack_session.CONNECTION_LOST}) def start(self, host, port): self.host = host diff --git a/conpot/protocols/s7comm/s7_server.py b/conpot/protocols/s7comm/s7_server.py index a815e0f0..da89166f 100644 --- a/conpot/protocols/s7comm/s7_server.py +++ b/conpot/protocols/s7comm/s7_server.py @@ -27,6 +27,7 @@ from conpot.protocols.s7comm.cotp import COTP_ConnectionConfirm from conpot.protocols.s7comm.s7 import S7 import conpot.core as conpot_core +from conpot.core import attack_session from conpot.core.protocol_wrapper import conpot_protocol from lxml import etree @@ -82,14 +83,14 @@ def handle(self, sock, address): address[0], address[1], session.id ) ) - session.add_event({"type": "NEW_CONNECTION"}) + session.add_event({"type": attack_session.NEW_CONNECTION}) try: while True: data = sock.recv(4, socket.MSG_WAITALL) if len(data) == 0: - session.add_event({"type": "CONNECTION_LOST"}) + session.add_event({"type": attack_session.CONNECTION_LOST}) break _, _, length = unpack("!BBH", data[:4]) @@ -283,12 +284,12 @@ def handle(self, sock, address): ) except socket.timeout: - session.add_event({"type": "CONNECTION_LOST"}) + session.add_event({"type": attack_session.CONNECTION_LOST}) logger.debug( "Socket timeout, remote: {0}. ({1})".format(address[0], session.id) ) except socket.error: - session.add_event({"type": "CONNECTION_LOST"}) + session.add_event({"type": attack_session.CONNECTION_LOST}) logger.debug( "Connection reset by peer, remote: {0}. ({1})".format( address[0], session.id diff --git a/conpot/protocols/tftp/tftp_server.py b/conpot/protocols/tftp/tftp_server.py index c5a0aaf2..fa20b592 100644 --- a/conpot/protocols/tftp/tftp_server.py +++ b/conpot/protocols/tftp/tftp_server.py @@ -24,6 +24,7 @@ from conpot.protocols.tftp import tftp_handler from gevent.server import DatagramServer import conpot.core as conpot_core +from conpot.core import attack_session from conpot.core.protocol_wrapper import conpot_protocol from conpot.utils.networking import get_interface_ip from tftpy import TftpException, TftpTimeout @@ -116,7 +117,7 @@ def handle(self, buffer, client_addr): client_addr[0], client_addr[1] ) ) - session.add_event({"type": "NEW_CONNECTION"}) + session.add_event({"type": attack_session.NEW_CONNECTION}) logger.debug("Read %d bytes", len(buffer)) context = tftp_handler.TFTPContextServer( client_addr[0], client_addr[1], self.timeout, self.root, None, None @@ -124,13 +125,13 @@ def handle(self, buffer, client_addr): context.vfs, context.data_fs = self.vfs, self.data_fs if self.shutdown: logger.info("Shutting down now. Disconnecting {}".format(client_addr)) - session.add_event({"type": "CONNECTION_TERMINATED"}) + session.add_event({"type": attack_session.CONNECTION_TERMINATED}) try: context.start(buffer) context.cycle() except TftpTimeout as err: logger.info("Timeout occurred %s: %s" % (context, str(err))) - session.add_event({"type": "CONNECTION_TIMEOUT"}) + session.add_event({"type": attack_session.CONNECTION_TIMEOUT}) context.retry_count += 1 # TODO: We should accept retries from the user. if context.retry_count >= self.TIMEOUT_RETRIES: @@ -148,7 +149,7 @@ def handle(self, buffer, client_addr): context, str(err) ) ) - session.add_event({"type": "CONNECTION_LOST"}) + session.add_event({"type": attack_session.CONNECTION_LOST}) logger.info("TFTP: terminating connection: {}".format(context)) session.set_ended() context.end() diff --git a/conpot/protocols/triconex/triconex.xsd b/conpot/protocols/triconex/triconex.xsd new file mode 100644 index 00000000..98bdc39e --- /dev/null +++ b/conpot/protocols/triconex/triconex.xsd @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/conpot/protocols/triconex/triconex_server.py b/conpot/protocols/triconex/triconex_server.py new file mode 100644 index 00000000..93ba646c --- /dev/null +++ b/conpot/protocols/triconex/triconex_server.py @@ -0,0 +1,363 @@ +# BSD 3-Clause License +# +# Copyright (c) 2018, Nozomi Networks +# Copyright (c) 2020, MushMush +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import socket +import struct +from lxml import etree +from gevent.server import DatagramServer +import conpot.core as conpot_core +from conpot.utils.networking import get_interface_ip +from conpot.core.protocol_wrapper import conpot_protocol +from conpot.core import attack_session +import crcmod +import time +import logging + +logger = logging.getLogger(__name__) +cf = crcmod.mkCrcFun(0x18005, rev=True, initCrc=0, xorOut=0) + + +def build_slot(leds0, leds1, model, color): + slotfmt = "<" + 32 * "B" + return struct.pack( + slotfmt, + leds0, + leds1, + model, + color, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ) + + +# Construct slots +mps = { + "active": build_slot(0x15, 0x21, 0xF0, 0x01), + "passive": build_slot(0x02, 0x01, 0xF0, 0x02), +} + +slotsdesc = { + "empty": build_slot(0, 0, 0, 0), + "com": build_slot(5, 33, 55, 1), + "do": build_slot(5, 16, 20, 1), + "di": build_slot(5, 32, 11, 1), + "him": build_slot(5, 22, 53, 1), + "ddo": build_slot(0x4F, 0x21, 0x5C, 0x2), +} + + +def build_chassis_status_response( + triconId=0, + seq=0, + node=2, + projname="FIRSTPROJ", + activemp=0, + mpmodel=1, + slots=["com"], +): + # Project segment + data = struct.pack( + " + + + + + + diff --git a/conpot/templates/triconex/triconex/triconex.xml b/conpot/templates/triconex/triconex/triconex.xml new file mode 100644 index 00000000..829b77bc --- /dev/null +++ b/conpot/templates/triconex/triconex/triconex.xml @@ -0,0 +1,8 @@ + + + empty + empty + empty + empty + + \ No newline at end of file diff --git a/conpot/tests/test_triconex.py b/conpot/tests/test_triconex.py new file mode 100644 index 00000000..ee599634 --- /dev/null +++ b/conpot/tests/test_triconex.py @@ -0,0 +1,18 @@ +import unittest + +from conpot.utils.greenlet import spawn_test_server, teardown_test_server +from conpot.protocols.triconex.triconex_server import TriconexServer + + +class TestTriconexServer(unittest.TestCase): + def setUp(self): + self.triconex_server, self.greenlet = spawn_test_server( + TriconexServer, template="default", protocol="triconex" + ) + + def tearDown(self): + teardown_test_server(self.triconex_server, self.greenlet) + + +if __name__ == "__main__": + unittest.main() diff --git a/requirements.txt b/requirements.txt index 7b729187..7dbd94a8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -27,4 +27,5 @@ freezegun!=0.3.13 pytest pycrypto sphinx_rtd_theme +crcmod==1.7 psutil