コード例 #1
0
 def testCheckTrIdRollover(self):
     """Check that the transaction id will rollover when max valuie is reached"""
     query = modbus_tcp.TcpQuery()
     tr_id_before = query._get_transaction_id()
     for a in range(int("ffff", 16)):
         query._get_transaction_id()    
     self.assertEqual(query._get_transaction_id(), tr_id_before)
コード例 #2
0
 def testParseTooShortRequest(self):
     """Test an error is raised if the request is too short"""
     query = modbus_tcp.TcpQuery()
     self.assertRaises(modbus_tk.modbus.ModbusInvalidRequestError,
                       query.parse_request, "")
     self.assertRaises(modbus_tk.modbus.ModbusInvalidRequestError,
                       query.parse_request, "a" * 6)
コード例 #3
0
    def handle(self, sock, address):
        sock.settimeout(self.timeout)

        session = conpot_core.get_session('modbus', address[0], address[1])

        self.start_time = time.time()
        logger.info('New connection from {0}:{1}. ({2})'.format(address[0], address[1], session.id))

        try:
            while True:
                request = sock.recv(7)
                if not request:
                    logger.info('Client disconnected. ({0})'.format(session.id))
                    break
                if request.strip().lower() == 'quit.':
                    logger.info('Client quit. ({0})'.format(session.id))
                    break
                tr_id, pr_id, length = struct.unpack(">HHH", request[:6])
                while len(request) < (length + 6):
                    new_byte = sock.recv(1)
                    request += new_byte
                query = modbus_tcp.TcpQuery()

                # logdata is a dictionary containing request, slave_id, function_code and response
                response, logdata = self._databank.handle_request(query, request)
                logdata['request'] = request.encode('hex')
                session.add_event(logdata)

                logger.debug('Modbus traffic from {0}: {1} ({2})'.format(address[0], logdata, session.id))

                if response:
                    sock.sendall(response)
        except socket.timeout:
            logger.debug('Socket timeout, remote: {0}. ({1})'.format(address[0], session.id))
コード例 #4
0
 def testBuildRequest(self):
     """Test the mbap returned by building a request"""
     query = modbus_tcp.TcpQuery()
     request = query.build_request(to_data(""), 0)
     self.assertEqual(
         struct.pack(">HHHB", query._request_mbap.transaction_id, 0, 1, 0),
         request)
コード例 #5
0
 def testParseRequestInvalidLength(self):
     """Test that an error is raised if the length is not valid"""
     query = modbus_tcp.TcpQuery()
     i = 0
     for pdu in ["", "a", "a" * 127, "abcdefghi"]:
         request = struct.pack(">HHHB", 0, 0, (len(pdu) + 2), 0)
         self.assertRaises(modbus_tk.modbus_tcp.ModbusInvalidMbapError,
                           query.parse_request, request + to_data(pdu))
コード例 #6
0
 def testBuildRequestWithSlave(self):
     """Test the mbap returned by building a request with a slave"""
     query = modbus_tcp.TcpQuery()
     for i in range(0, 255):
         request = query.build_request(to_data(""), i)
         self.assertEqual(
             struct.pack(">HHHB", query._request_mbap.transaction_id, 0, 1,
                         i), request)
コード例 #7
0
 def testIncIdOfRequest(self):
     """Check that the transaction id is increased when building the request"""
     queries = [modbus_tcp.TcpQuery() for i in range(100)]
     
     for i in range(len(queries)):
         queries[i].build_request(to_data(""), 0)
     
     for i in range(len(queries)-1):
         self.assertEqual(queries[i]._request_mbap.transaction_id+1, queries[i+1]._request_mbap.transaction_id)
コード例 #8
0
 def testBuildRequestWithPdu(self):
     """Test the mbap returned by building a request with a pdu"""
     query = modbus_tcp.TcpQuery()
     for pdu in ["", "a", "a" * 127, "abcdefghi"]:
         request = query.build_request(to_data(pdu), 0)
         self.assertEqual(
             struct.pack(">HHHB" + str(len(pdu)) + "s",
                         query._request_mbap.transaction_id, 0,
                         len(pdu) + 1, 0, to_data(pdu)), request)
コード例 #9
0
 def testBuildResponse(self):
     """Test that the response of a request is build properly"""
     query = modbus_tcp.TcpQuery()
     i = 0
     for pdu in ["", "a", "a"*127, "abcdefghi"]:
         request = query.build_request(to_data(pdu), i)
         response = query.build_response(to_data(pdu))
         response_pdu = query.parse_response(response)
         self.assertEqual(to_data(pdu), response_pdu)
         i += 1
コード例 #10
0
 def testParseRequest(self):
     """Test that Modbus TCP part of the request is understood"""
     query = modbus_tcp.TcpQuery()
     i = 0
     for pdu in ["", "a", "a"*127, "abcdefghi"]:
         request = query.build_request(to_data(pdu), i)
         (slave, extracted_pdu) = query.parse_request(request)
         self.assertEqual(extracted_pdu, to_data(pdu))
         self.assertEqual(slave, i)
         i += 1
コード例 #11
0
 def testParseWrongProtocolIdResponse(self):
     """Test an error is raised if wrong protocol id"""
     query = modbus_tcp.TcpQuery()
     pdu = "a"
     request = query.build_request(pdu, 0)
     response = struct.pack(">HHHB" + str(len(pdu)) + "s",
                            query._request_mbap.transaction_id,
                            query._request_mbap.protocol_id + 1,
                            len(pdu) + 1, query._request_mbap.unit_id, pdu)
     self.assertRaises(modbus_tk.modbus_tcp.ModbusInvalidMbapError,
                       query.parse_response, response)
コード例 #12
0
 def testParseWrongLengthResponse(self):
     """Test an error is raised if the length is not ok"""
     query = modbus_tcp.TcpQuery()
     pdu = to_data('a')
     request = query.build_request(pdu, 0)
     response = struct.pack(">HHHB" + str(len(pdu)) + "s",
                            query._request_mbap.transaction_id,
                            query._request_mbap.protocol_id + 1, len(pdu),
                            query._request_mbap.unit_id, to_data('pdu'))
     self.assertRaises(modbus_tk.modbus_tcp.ModbusInvalidMbapError,
                       query.parse_response, response)
コード例 #13
0
 def testParseRespone(self):
     """Test that Modbus TCP part of the response is understood"""
     query = modbus_tcp.TcpQuery()
     for pdu in ["", "a", "a" * 127, "abcdefghi"]:
         request = query.build_request(to_data(pdu), 0)
         response = struct.pack(">HHHB" + str(len(pdu)) + "s",
                                query._request_mbap.transaction_id,
                                query._request_mbap.protocol_id,
                                len(pdu) + 1, query._request_mbap.unit_id,
                                to_data(pdu))
         extracted = query.parse_response(response)
         self.assertEqual(extracted, to_data(pdu))
コード例 #14
0
 def testIncTrIdIsThreadSafe(self):
     """Check that the function in charge of increasing the transaction id is thread safe"""
     def inc_by():
         query = modbus_tcp.TcpQuery()
         for i in range(1000):
             query._get_transaction_id()
         
     query = modbus_tcp.TcpQuery()
     tr_id_before = query._get_transaction_id()
     threads = [threading.Thread(target=inc_by) for thread_nr in range(20)]
     for thread in threads: thread.start()
     for thread in threads: thread.join()
     self.assertEqual(1000*20+1, query._get_transaction_id()-tr_id_before)
コード例 #15
0
    def handle(self, sock, address):
        sock.settimeout(self.timeout)
        session_id = str(uuid.uuid4())
        session_data = {
            'session_id': session_id,
            'remote': address,
            'timestamp': datetime.utcnow(),
            'data_type': 'modbus',
            'data': {}
        }

        start_time = time.time()
        logger.info('New connection from {0}:{1}. ({2})'.format(
            address[0], address[1], session_id))

        try:
            while True:
                request = sock.recv(7)
                if not request:
                    logger.info(
                        'Client disconnected. ({0})'.format(session_id))
                    break
                if request.strip().lower() == 'quit.':
                    logger.info('Client quit. ({0})'.format(session_id))
                    break
                tr_id, pr_id, length = struct.unpack(">HHH", request[:6])
                while len(request) < (length + 6):
                    new_byte = sock.recv(1)
                    request += new_byte
                query = modbus_tcp.TcpQuery()

                #logdata is a dictionary containing request, slave_id, function_code and response
                response, logdata = self._databank.handle_request(
                    query, request)
                elapse_ms = int(time.time() - start_time) * 1000
                session_data['data'][elapse_ms] = logdata

                logger.debug('Modbus traffic from {0}: {1} ({2})'.format(
                    address[0], logdata, session_id))

                if response:
                    sock.sendall(response)
        except socket.timeout:
            logger.debug('Socket timeout, remote: {0}. ({1})'.format(
                address[0], session_id))

        self.log_queue.put(session_data)
コード例 #16
0
    def handle(self, sock, address):
        sock.settimeout(self.timeout)

        session = conpot_core.get_session('modbus', address[0], address[1])

        self.start_time = time.time()
        logger.info('New Modbus connection from %s:%s. (%s)', address[0],
                    address[1], session.id)
        session.add_event({'type': 'NEW_CONNECTION'})

        try:
            while True:
                request = sock.recv(7)
                if not request:
                    logger.info('Modbus client disconnected. (%s)', session.id)
                    session.add_event({'type': 'CONNECTION_LOST'})
                    break
                if request.strip().lower() == 'quit.':
                    logger.info('Modbus client quit. (%s)', session.id)
                    session.add_event({'type': 'CONNECTION_QUIT'})
                    break
                tr_id, pr_id, length = struct.unpack(">HHH", request[:6])
                while len(request) < (length + 6):
                    new_byte = sock.recv(1)
                    request += new_byte
                query = modbus_tcp.TcpQuery()

                # logdata is a dictionary containing request, slave_id,
                # function_code and response
                response, logdata = self._databank.handle_request(
                    query, request, self.mode)
                logdata['request'] = request.encode('hex')
                session.add_event(logdata)

                logger.info('Modbus traffic from %s: %s (%s)', address[0],
                            logdata, session.id)

                if response:
                    sock.sendall(response)
                    logger.info('Modbus response sent to %s', address[0])
                else:
                    # MB serial connection addressing UID=0
                    if (self.mode == 'serial' and logdata['slave_id'] == 0):
                        # delay is in milliseconds
                        time.sleep(self.delay / 1000)
                        logger.debug(
                            'Modbus server\'s turnaround delay expired.')
                        logger.info(
                            'Modbus connection terminated with client %s.',
                            address[0])
                        session.add_event({'type': 'CONNECTION_TERMINATED'})
                        sock.shutdown(socket.SHUT_RDWR)
                        sock.close()
                        break
                    # Invalid addressing
                    else:
                        logger.info(
                            'Modbus client ignored due to invalid addressing.'
                            ' (%s)', session.id)
                        session.add_event({'type': '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'})
コード例 #17
0
 def inc_by():
     query = modbus_tcp.TcpQuery()
     for i in range(1000):
         query._get_transaction_id()
コード例 #18
0
ファイル: modbus_server.py プロジェクト: renwinping/conpot
    def handle(self, sock, address):
        sock.settimeout(self.timeout)

        session = conpot_core.get_session(
            "modbus",
            address[0],
            address[1],
            sock.getsockname()[0],
            sock.getsockname()[1],
        )

        self.start_time = time.time()
        logger.info("New Modbus connection from %s:%s. (%s)", address[0],
                    address[1], session.id)
        session.add_event({"type": "NEW_CONNECTION"})

        try:
            while True:
                request = None
                try:
                    request = sock.recv(7)
                except Exception as e:
                    logger.error(
                        "Exception occurred in ModbusServer.handle() "
                        "at sock.recv(): %s",
                        str(e),
                    )

                if not request:
                    logger.info("Modbus client disconnected. (%s)", session.id)
                    session.add_event({"type": "CONNECTION_LOST"})
                    break
                if request.strip().lower() == "quit.":
                    logger.info("Modbus client quit. (%s)", session.id)
                    session.add_event({"type": "CONNECTION_QUIT"})
                    break
                if len(request) < 7:
                    logger.info(
                        "Modbus client provided data {} but invalid.".format(
                            session.id))
                    session.add_event({"type": "CONNECTION_TERMINATED"})
                    break
                _, _, length = struct.unpack(">HHH", request[:6])
                while len(request) < (length + 6):
                    try:
                        new_byte = sock.recv(1)
                        request += new_byte
                    except Exception:
                        break
                query = modbus_tcp.TcpQuery()

                # logdata is a dictionary containing request, slave_id,
                # function_code and response
                response, logdata = self._databank.handle_request(
                    query, request, self.mode)
                logdata["request"] = codecs.encode(request, "hex")
                session.add_event(logdata)

                logger.info("Modbus traffic from %s: %s (%s)", address[0],
                            logdata, session.id)

                if response:
                    sock.sendall(response)
                    logger.info("Modbus response sent to %s", address[0])
                else:
                    # TODO:
                    # response could be None under several different cases

                    # MB serial connection addressing UID=0
                    if (self.mode == "serial") and (logdata["slave_id"] == 0):
                        # delay is in milliseconds
                        time.sleep(self.delay / 1000)
                        logger.debug(
                            "Modbus server's turnaround delay expired.")
                        logger.info(
                            "Modbus connection terminated with client %s.",
                            address[0])
                        session.add_event({"type": "CONNECTION_TERMINATED"})
                        sock.shutdown(socket.SHUT_RDWR)
                        sock.close()
                        break
                    # Invalid addressing
                    else:
                        logger.info(
                            "Modbus client ignored due to invalid addressing."
                            " (%s)",
                            session.id,
                        )
                        session.add_event({"type": "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"})
コード例 #19
0
 def testBuildRequestWithInvalidSlave(self):
     """Test that an error is raised when invalid slave is passed"""
     query = modbus_tcp.TcpQuery()
     for i in [-1, 256, 257, 65536]:
         self.assertRaises(modbus_tk.modbus.InvalidArgumentError, query.build_request, "", i)