M
I would like to use my python skills to test a Ethernet/IP implementation we are developing. After searching in vain for some python library that will allow me to talk CIP over Ethernet I decided to try an implement my own. I did this by reverse engineering the packets being generated by a EIP package we have been using.
Firstly does anyone know of an existing EIP/CIP python library I could use?
If not does anyone know how I set up a CIP socket?
I initially tried by doing this, the WHOLE_FRAME being constructed from what I saw in wireshark output.
import socket
import string
import select
TCP_IP = '10.0.0.2'
TCP_PORT = 44818
BUFFER_SIZE = 1024
# EtherNet/IP send data
# Encapsulation Header
EIP_COMMAND = '\x6f\x00'
EIP_LENGTH = '\x18\x00'
EIP_SESSION_HANDLE = '\x01\x00\x02\xe8'
EIP_SUCCESS = '\x00\x00\x00\x00'
EIP_SENDER_CONTEXT = '\x38\x00\x02\x00\x00\x00\x85\x01'
EIP_OPTIONS = '\x00\x00\x00\x00'
EIP_ENCAP_HEADER = EIP_COMMAND + EIP_LENGTH + EIP_SESSION_HANDLE + EIP_SUCCESS + EIP_SENDER_CONTEXT + EIP_OPTIONS
# command specific data
EIP_INTHAND = '\x00\x00\x00\x00' # CIP
EIP_TIMEOUT = '\x1e\x00'
EIP_ITEM_COUNT = '\x02\x00'
EIP_TYPE_ITEM1_ID = '\x00\x00'
EIP_TYPE_ITEM1_LEN = '\x00\x00'
EIP_TYPE_ITEM2_ID = '\xb2\x00'
EIP_TYPE_ITEM2_LEN = '\x08\x00'
EIP_COMMAND_SPEC_DATA = EIP_INTHAND + EIP_TIMEOUT + EIP_ITEM_COUNT + EIP_TYPE_ITEM1_ID + EIP_TYPE_ITEM1_LEN + EIP_TYPE_ITEM2_ID + EIP_TYPE_ITEM2_LEN
# CIP
CIP_SERVICE = '\x0e' # get single attribut
CIP_REQ_SIZE = '\x03'
CIP_REQ_PATH = '\x20\x29\x24\x01\x30\x03' # Param 1 Run Forward
CIP = CIP_SERVICE + CIP_REQ_SIZE + CIP_REQ_PATH
# glue all together
WHOLE_FRAME = EIP_ENCAP_HEADER + EIP_COMMAND_SPEC_DATA + CIP
whole_message = ""
for b in WHOLE_FRAME:
whole_message += " " + hex(ord(b))
print whole_message
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
foo = raw_input('socket created...')
s.connect((TCP_IP, TCP_PORT))
foo = raw_input('connected...')
s.send(WHOLE_FRAME)
foo = raw_input('sent...')
s.setblocking(0)
ready = select.select(, [], [], 5)
foo = raw_input('something returned...')
if ready[0]:
data = s.recv(BUFFER_SIZE)
whole_message = ""
for b in data:
whole_message += " " + hex(ord(b))
print whole_message
s.close()
This only partially worked as I got loads of frames generated I do not need.
The original seem to do the connection at the same time as doing the get attribute where as mine seems to do two connections and then does the get attribute.
I think the socket connection needs to carry the CIP framing, but I do not know how to do it. Any pointers would be appreciated,.
Regards Mark
Firstly does anyone know of an existing EIP/CIP python library I could use?
If not does anyone know how I set up a CIP socket?
I initially tried by doing this, the WHOLE_FRAME being constructed from what I saw in wireshark output.
import socket
import string
import select
TCP_IP = '10.0.0.2'
TCP_PORT = 44818
BUFFER_SIZE = 1024
# EtherNet/IP send data
# Encapsulation Header
EIP_COMMAND = '\x6f\x00'
EIP_LENGTH = '\x18\x00'
EIP_SESSION_HANDLE = '\x01\x00\x02\xe8'
EIP_SUCCESS = '\x00\x00\x00\x00'
EIP_SENDER_CONTEXT = '\x38\x00\x02\x00\x00\x00\x85\x01'
EIP_OPTIONS = '\x00\x00\x00\x00'
EIP_ENCAP_HEADER = EIP_COMMAND + EIP_LENGTH + EIP_SESSION_HANDLE + EIP_SUCCESS + EIP_SENDER_CONTEXT + EIP_OPTIONS
# command specific data
EIP_INTHAND = '\x00\x00\x00\x00' # CIP
EIP_TIMEOUT = '\x1e\x00'
EIP_ITEM_COUNT = '\x02\x00'
EIP_TYPE_ITEM1_ID = '\x00\x00'
EIP_TYPE_ITEM1_LEN = '\x00\x00'
EIP_TYPE_ITEM2_ID = '\xb2\x00'
EIP_TYPE_ITEM2_LEN = '\x08\x00'
EIP_COMMAND_SPEC_DATA = EIP_INTHAND + EIP_TIMEOUT + EIP_ITEM_COUNT + EIP_TYPE_ITEM1_ID + EIP_TYPE_ITEM1_LEN + EIP_TYPE_ITEM2_ID + EIP_TYPE_ITEM2_LEN
# CIP
CIP_SERVICE = '\x0e' # get single attribut
CIP_REQ_SIZE = '\x03'
CIP_REQ_PATH = '\x20\x29\x24\x01\x30\x03' # Param 1 Run Forward
CIP = CIP_SERVICE + CIP_REQ_SIZE + CIP_REQ_PATH
# glue all together
WHOLE_FRAME = EIP_ENCAP_HEADER + EIP_COMMAND_SPEC_DATA + CIP
whole_message = ""
for b in WHOLE_FRAME:
whole_message += " " + hex(ord(b))
print whole_message
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
foo = raw_input('socket created...')
s.connect((TCP_IP, TCP_PORT))
foo = raw_input('connected...')
s.send(WHOLE_FRAME)
foo = raw_input('sent...')
s.setblocking(0)
ready = select.select(
foo = raw_input('something returned...')
if ready[0]:
data = s.recv(BUFFER_SIZE)
whole_message = ""
for b in data:
whole_message += " " + hex(ord(b))
print whole_message
s.close()
This only partially worked as I got loads of frames generated I do not need.
The original seem to do the connection at the same time as doing the get attribute where as mine seems to do two connections and then does the get attribute.
I think the socket connection needs to carry the CIP framing, but I do not know how to do it. Any pointers would be appreciated,.
Regards Mark