EtherNet / IP是为了在以太网中使用CIP协议而进行的封装.EtherNet / IP的CIP帧封装了命令,数据点和消息等信息.CIP帧包括CIP设备配置文件数据包的其余部分是以太网/ IP帧,CIP帧通过它们在以太网上传输。EIP一般使用TCP / UDP的44818端口运行,还有一个2222端口,这两个端口分别实现隐式消息传递和显示消息传递两种方式。客户端/服务器消息,而隐消息为I / O消息。
详细信息可参考下面文章
https://www.cnblogs.com/blacksunny/p/7202815.html
下面是Python 实现的代码,转载自https://github.com/paperwork/pyenip/blob/605ad6d026865e3378542d4428ec975e7c26d2e4/ethernetip.py
""" | |
Copyright (C) 2014 Sebastian Block | |
This program is free software; you can redistribute it and/or modify | |
it under the terms of the GNU General Public License as published by | |
the Free Software Foundation; either version 2 of the License. | |
This program is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
GNU General Public License for more details. | |
You should have received a copy of the GNU General Public License along | |
with this program; if not, write to the Free Software Foundation, Inc., | |
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
""" | |
import random | |
import select | |
import socket | |
import struct | |
import threading | |
import time | |
from .dpkt import dpkt | |
ENIP_TCP_PORT = 44818 | |
ENIP_UDP_PORT = 2222 | |
#/* Common Services */ | |
CI_SRV_GET_ALL = 0x01 | |
CI_SRV_SET_ATTR_ALL = 0x02 | |
CI_SRV_GET_ATTR_LIST = 0x03 | |
CI_SRV_SET_ATTR_LIST = 0x04 | |
CI_SRV_RESET = 0x05 | |
CI_SRV_START = 0x06 | |
CI_SRV_STOP = 0x07 | |
CI_SRV_CREATE = 0x08 | |
CI_SRV_DELETE = 0x09 | |
CI_SRV_MULTIPLE_SRV = 0x0A | |
CI_SRV_APPLY_ATTR = 0x0D | |
CI_SRV_GET_ATTR_SINGLE = 0x0E | |
CI_SRV_SET_ATTR_SINGLE = 0x10 | |
CI_SRV_FIND_NEXT_OBJ = 0x11 | |
CI_SRV_RESTORE = 0x15 | |
CI_SRV_SAVE = 0x16 | |
CI_SRV_NOP = 0x17 | |
CI_SRV_GET_MEMBER = 0x18 | |
CI_SRV_SET_MEMBER = 0x19 | |
CI_SRV_INSERT_MEMBER = 0x1A | |
CI_SRV_REMOVE_MEMBER = 0x1B | |
CI_SRV_GROUP_SYNC = 0x1C | |
CI_SRV_FORWARD_CLOSE = 0x4E | |
CI_SRV_UNCONN_SEND = 0x52 | |
CI_SRV_FORWARD_OPEN = 0x54 | |
#/* List of Objects */ | |
CIP_OBJ_IDENTITY = 0x01 | |
CIP_OBJ_MESSAGE_ROUTER = 0x02 | |
CIP_OBJ_ASSEMBLY = 0x04 | |
CIP_OBJ_CONNECTION = 0x05 | |
CIP_OBJ_CONNMANAGER = 0x06 | |
CIP_OBJ_DLR = 0x47 | |
CIP_OBJ_QOS = 0x48 | |
CIP_OBJ_BASE_SWITCH = 0x51 | |
CIP_OBJ_SNMP = 0x52 | |
CIP_OBJ_POWER_MANAGEM = 0x53 | |
CIP_OBJ_RSTP_BRIDGE = 0x54 | |
CIP_OBJ_RSTP_PORT = 0x55 | |
CIP_OBJ_PRP = 0x56 | |
CIP_OBJ_PRP_NODE_TABLE = 0x57 | |
CIP_OBJ_CONN_CONF = 0xF3 | |
CIP_OBJ_PORT = 0xF4 | |
CIP_OBJ_TCPIP = 0xF5 | |
CIP_OBJ_ETHERNET_LINK = 0xF6 | |
#/* The following are CIP (Ethernet/IP) Generic error codes */ | |
CIP_ROUTER_ERROR_SUCCESS = 0x00 # We done good... | |
CIP_ROUTER_ERROR_FAILURE = 0x01 # Connection failure | |
CIP_ROUTER_ERROR_NO_RESOURCE = 0x02 # Resource(s) unavailable | |
CIP_ROUTER_ERROR_INVALID_PARAMETER_VALUE = 0x03 # Obj specific data bad | |
CIP_ROUTER_ERROR_INVALID_SEG_TYPE = 0x04 # Invalid segment type in path | |
CIP_ROUTER_ERROR_INVALID_DESTINATION = 0x05 # Invalid segment value in path | |
CIP_ROUTER_ERROR_PARTIAL_DATA = 0x06 # Not all expected data sent | |
CIP_ROUTER_ERROR_CONN_LOST = 0x07 # Messaging connection lost | |
CIP_ROUTER_ERROR_BAD_SERVICE = 0x08 # Unimplemented service code | |
CIP_ROUTER_ERROR_BAD_ATTR_DATA = 0x09 # Bad attribute data value | |
CIP_ROUTER_ERROR_ATTR_LIST_ERROR = 0x0A # Get/set attr list failed | |
CIP_ROUTER_ERROR_ALREADY_IN_REQUESTED_MODE = 0x0B # Obj already in requested mode | |
CIP_ROUTER_ERROR_OBJECT_STATE_CONFLICT = 0x0C # Obj not in proper mode | |
CIP_ROUTER_ERROR_OBJ_ALREADY_EXISTS = 0x0D # Object already created | |
CIP_ROUTER_ERROR_ATTR_NOT_SETTABLE = 0x0E # Set of get only attr tried | |
CIP_ROUTER_ERROR_PERMISSION_DENIED = 0x0F # Insufficient access permission | |
CIP_ROUTER_ERROR_DEV_IN_WRONG_STATE = 0x10 # Device not in proper mode | |
CIP_ROUTER_ERROR_REPLY_DATA_TOO_LARGE = 0x11 # Response packet too large | |
CIP_ROUTER_ERROR_FRAGMENT_PRIMITIVE = 0x12 # Primitive value will fragment | |
CIP_ROUTER_ERROR_NOT_ENOUGH_DATA = 0x13 # Goldilocks complaint #1 | |
CIP_ROUTER_ERROR_ATTR_NOT_SUPPORTED = 0x14 # Attribute is undefined | |
CIP_ROUTER_ERROR_TOO_MUCH_DATA = 0x15 # Goldilocks complaint #2 | |
CIP_ROUTER_ERROR_OBJ_DOES_NOT_EXIST = 0x16 # Non-existant object specified | |
CIP_ROUTER_ERROR_NO_FRAGMENTATION = 0x17 # Fragmentation not active | |
CIP_ROUTER_ERROR_DATA_NOT_SAVED = 0x18 # Attr data not previously saved | |
CIP_ROUTER_ERROR_DATA_WRITE_FAILURE = 0x19 # Attr data not saved this time | |
CIP_ROUTER_ERROR_REQUEST_TOO_LARGE = 0x1A # Routing failure on request | |
CIP_ROUTER_ERROR_RESPONSE_TOO_LARGE = 0x1B # Routing failure on response | |
CIP_ROUTER_ERROR_MISSING_LIST_DATA = 0x1C # Attr data not found in list | |
CIP_ROUTER_ERROR_INVALID_LIST_STATUS = 0x1D # Returned list of attr w/status | |
CIP_ROUTER_ERROR_SERVICE_ERROR = 0x1E # Embedded service failed | |
CIP_ROUTER_ERROR_VENDOR_SPECIFIC = 0x1F # Vendor specific error | |
CIP_ROUTER_ERROR_INVALID_PARAMETER = 0x20 # Invalid parameter | |
CIP_ROUTER_ERROR_WRITE_ONCE_FAILURE = 0x21 # Write once previously done | |
CIP_ROUTER_ERROR_INVALID_REPLY = 0x22 # Invalid reply received | |
CIP_ROUTER_ERROR_BAD_KEY_IN_PATH = 0x25 # Electronic key in path failed | |
CIP_ROUTER_ERROR_BAD_PATH_SIZE = 0x26 # Invalid path size | |
CIP_ROUTER_ERROR_UNEXPECTED_ATTR = 0x27 # Cannot set attr at this time | |
CIP_ROUTER_ERROR_INVALID_MEMBER = 0x28 # Member ID in list nonexistant | |
CIP_ROUTER_ERROR_MEMBER_NOT_SETTABLE = 0x29 # Cannot set value of member | |
CIP_ROUTER_ERROR_UNKNOWN_MODBUS_ERROR = 0x2B # Unhandled Modbus Error | |
CIP_ROUTER_ERROR_STILL_PROCESSING = 0xFF # Special marker to indicate we haven't finished processing the request yet | |
# Extended status in Forward open response | |
CIP_FWD_OPEN_EXTENDED_STATUS_INVALID_CONFIGURATION_SIZE = 0x126 | |
class EncapsulationPacket(dpkt.Packet): | |
# commands | |
ENCAP_CMD_NOP = 0x0000 | |
ENCAP_CMD_LISTSERVICES = 0x0004 | |
ENCAP_CMD_LISTIDENTITY = 0x0063 | |
ENCAP_CMD_LISTINTERFACES = 0x0064 | |
ENCAP_CMD_REGISTERSESSION = 0x0065 | |
ENCAP_CMD_UNREGISTERSESSION = 0x0066 | |
ENCAP_CMD_SENDRRDATA = 0x006F | |
ENCAP_CMD_SENDUNITDATA = 0x0070 | |
ENCAP_CMD_INDICATESTATUS = 0x0072 | |
ENCAP_CMD_CANCEL = 0x0073 | |
# status | |
ENCAP_STATUS_SUCCESS = 0x0000 | |
ENCAP_STATUS_INVALID_CMD = 0x0001 | |
ENCAP_STATUS_OUT_OF_MEMORY = 0x0002 | |
ENCAP_STATUS_INCORRECT_DATA = 0x0003 | |
ENCAP_STATUS_INVALID_LENGTH = 0x0065 | |
ENCAP_STATUS_UNSUPPORTED_VERSION = 0x0069 | |
__byte_order__ = '<' | |
__hdr__ = (('command', 'H', 0), | |
('length', 'H', 0), | |
('session', 'I', 0), | |
('status', 'I', 0), | |
('sender_context', '8s', bytes([0,0,0,0,0,0,0,0])), | |
('options', 'I', 0)) | |
class CommandSpecificData(dpkt.Packet): | |
# type ID | |
TYPE_ID_NULL = 0x0000 | |
TYPE_ID_LIST_IDENT_RESPONSE = 0x000C | |
TYPE_ID_CONNECTION_BASED = 0x00A1 | |
TYPE_ID_CONNECTED_TRANSPORT_PACKET = 0x00B1 | |
TYPE_ID_UNCONNECTED_MESSAGE = 0x00B2 | |
TYPE_ID_LISTSERVICES_RESPONSE = 0x0100 | |
TYPE_ID_SOCKADDR_INFO_ORIG_TARGET = 0x8000 | |
TYPE_ID_SOCKADDR_INFO_TARGET_ORIG = 0x8001 | |
TYPE_ID_SEQUENCED_ADDRESS = 0x8002 | |
__byte_order__ = '<' | |
__hdr__ = (('item_count', 'H', 0), | |
('type_id', 'H', 0), | |
('length', 'H', 0)) | |
class UnconnectedDataItem(dpkt.Packet): | |
UNCONN_DATA_ITEM_SERVICE_REQUEST = 0x00 | |
UNCONN_DATA_ITEM_SERVICE_RESPONSE = 0x80 | |
__byte_order__ = '<' | |
__hdr__ = (('type_id', 'H', 0), | |
('length', 'H', 0), | |
('service', 'B', 0)) | |
class UnconnectedDataItemHdr(dpkt.Packet): | |