LLDP module in SCAPY produce malformed packets - python

I am using scapy.contrib.lldp library to craft an LLDP packet, with the following fields:
Chassis ID (l1)
Port ID (l2)
Time to live (l3)
System name (l4)
Generic Organisation Specific - custom data 1 (l5)
Generic Organisation Specific - custom data 2 (l6)
End of LLDP (l7)
The options for each field comes from a csv file imported as DataFrame and I use the library class for each field.
The problem I have is that after I craft the packet (p=ethernet/l1/l2/l3/l4/l5/l6/l7) the l6 field has the double amount of bytes it is supposed to have, from the read data. I also tried to set a fixed value but the problem persists.
Below is a sample of the packet in wireshark (ok packet and malformed packet), the DataFrame and relevant code.
Layer 
Field 
Value
Ethernet 
dst 
01:23:00:00:00:01
Ethernet 
src 
32:cb:cd:7b:5a:47
Ethernet
type 
35020
LLDPDUChassisID 
_type 
1
LLDPDUChassisID 
_length 
7
LLDPDUChassisID 
subtype
  4
LLDPDUChassisID
family 
None
LLDPDUChassisID
id 
00:00:00:00:00:01
LLDPDUPortID 
_type
  2
LLDPDUPortID 
_length
  2
LLDPDUPortID 
subtype 
7
LLDPDUPortID
family 
None
LLDPDUPortID
id 
1
LLDPDUTimeToLive
  _type 
3
LLDPDUTimeToLive 
_length 
2
LLDPDUTimeToLive 
ttl 
4919
LLDPDUSystemName 
_type 
5
LLDPDUSystemName 
_length 
10
LLDPDUSystemName 
system_name 
openflow:1
LLDPDUGenericOrganisationSpecific 
_type 
127
LLDPDUGenericOrganisationSpecific 
_length 
16
LLDPDUGenericOrganisationSpecific
org_code 
9953
LLDPDUGenericOrganisationSpecific 
subtype 
0
LLDPDUGenericOrganisationSpecific
data 
openflow:1:1
LLDPDUGenericOrganisationSpecific 
_type 
127
LLDPDUGenericOrganisationSpecific 
_length 
20
LLDPDUGenericOrganisationSpecific
org_code 
9953
LLDPDUGenericOrganisationSpecific 
subtype 
1
LLDPDUGenericOrganisationSpecific
data 
b'`\xafE\x16\t\xa0#5\x02\x7f\xd5\p\xf7\x11A'
LLDPDUEndOfLLDPDU 
_type 
0
LLDPDUEndOfLLDPDU 
_length 
0
def getlldppack(host_2,ifa):
lim = 1
log = "/root/log.log"
file = "/root/dic_"+str(host_2)+"_"+str(lim)+".csv"
while lim<5:
try:
lldp1 = pd.read_csv(file)
except:
with open(log,'a') as lf:
lf.write("error when reading the packet "+file+" for count "+str(lim)+"\n")
time.sleep(8)
else:
lldp1 = lldp1.iloc[: , 1:]
e1=lldp1.loc[(lldp1['Layer']=='Ethernet')&(lldp1['Field']=='dst')].iloc[0,2]
e2=lldp1.loc[(lldp1['Layer']=='Ethernet')&(lldp1['Field']=='src')].iloc[0,2]
e3=int(lldp1.loc[(lldp1['Layer']=='Ethernet')&(lldp1['Field']=='type')].iloc[0,2])
e = Ether(dst=e1, src=e2, type=e3)
a1=int(lldp1.loc[(lldp1['Layer']=='LLDPDUChassisID')&(lldp1['Field']=='_type')].iloc[0,2])
a2=int(lldp1.loc[(lldp1['Layer']=='LLDPDUChassisID')&(lldp1['Field']=='_length')].iloc[0,2])
a3=int(lldp1.loc[(lldp1['Layer']=='LLDPDUChassisID')&(lldp1['Field']=='subtype')].iloc[0,2])
a4=lldp1.loc[(lldp1['Layer']=='LLDPDUChassisID')&(lldp1['Field']=='family')].iloc[0,2]
a5=lldp1.loc[(lldp1['Layer']=='LLDPDUChassisID')&(lldp1['Field']=='id')].iloc[0,2]
b1=int(lldp1.loc[(lldp1['Layer']=='LLDPDUPortID')&(lldp1['Field']=='_type')].iloc[0,2])
b2=int(lldp1.loc[(lldp1['Layer']=='LLDPDUPortID')&(lldp1['Field']=='_length')].iloc[0,2])
b3=int(lldp1.loc[(lldp1['Layer']=='LLDPDUPortID')&(lldp1['Field']=='subtype')].iloc[0,2])
b4=lldp1.loc[(lldp1['Layer']=='LLDPDUPortID')&(lldp1['Field']=='family')].iloc[0,2]
b5=int(lldp1.loc[(lldp1['Layer']=='LLDPDUPortID')&(lldp1['Field']=='id')].iloc[0,2])
c1=int(lldp1.loc[(lldp1['Layer']=='LLDPDUTimeToLive')&(lldp1['Field']=='_type')].iloc[0,2])
c2=int(lldp1.loc[(lldp1['Layer']=='LLDPDUTimeToLive')&(lldp1['Field']=='_length')].iloc[0,2])
c3=int(lldp1.loc[(lldp1['Layer']=='LLDPDUTimeToLive')&(lldp1['Field']=='ttl')].iloc[0,2])
d1=int(lldp1.loc[(lldp1['Layer']=='LLDPDUSystemName')&(lldp1['Field']=='_type')].iloc[0,2])
d2=int(lldp1.loc[(lldp1['Layer']=='LLDPDUSystemName')&(lldp1['Field']=='_length')].iloc[0,2])
d3=lldp1.loc[(lldp1['Layer']=='LLDPDUSystemName')&(lldp1['Field']=='system_name')].iloc[0,2]
e1=int(lldp1.loc[(lldp1['Layer']=='LLDPDUGenericOrganisationSpecific')&(lldp1['Field']=='_type')].iloc[0,2])
e2=int(lldp1.loc[(lldp1['Layer']=='LLDPDUGenericOrganisationSpecific')&(lldp1['Field']=='_length')].iloc[0,2])
e3=int(lldp1.loc[(lldp1['Layer']=='LLDPDUGenericOrganisationSpecific')&(lldp1['Field']=='org_code')].iloc[0,2])
e4=int(lldp1.loc[(lldp1['Layer']=='LLDPDUGenericOrganisationSpecific')&(lldp1['Field']=='subtype')].iloc[0,2])
e5=lldp1.loc[(lldp1['Layer']=='LLDPDUGenericOrganisationSpecific')&(lldp1['Field']=='data')].iloc[0,2]
f1=int(lldp1.loc[(lldp1['Layer']=='LLDPDUGenericOrganisationSpecific')&(lldp1['Field']=='_type')].iloc[1,2])
f2=int(lldp1.loc[(lldp1['Layer']=='LLDPDUGenericOrganisationSpecific')&(lldp1['Field']=='_length')].iloc[1,2])
f3=int(lldp1.loc[(lldp1['Layer']=='LLDPDUGenericOrganisationSpecific')&(lldp1['Field']=='org_code')].iloc[1,2])
f4=int(lldp1.loc[(lldp1['Layer']=='LLDPDUGenericOrganisationSpecific')&(lldp1['Field']=='subtype')].iloc[1,2])
f5=lldp1.loc[(lldp1['Layer']=='LLDPDUGenericOrganisationSpecific')&(lldp1['Field']=='data')].iloc[1,2]
g1=int(lldp1.loc[(lldp1['Layer']=='LLDPDUEndOfLLDPDU')&(lldp1['Field']=='_type')].iloc[0,2])
g2=int(lldp1.loc[(lldp1['Layer']=='LLDPDUEndOfLLDPDU')&(lldp1['Field']=='_length')].iloc[0,2])
l1 = LLDPDUChassisID(_type=a1,_length=a2,subtype=a3,family=a4,id=a5)
l2 = LLDPDUPortID(_type=b1,_length=b2,subtype=b3,family=b4,id=str(b5))
l3 = LLDPDUTimeToLive(_type=c1,_length=c2,ttl=c3)
auxo=d3
l4 = LLDPDUSystemName(_type=d1,_length=d2,system_name=auxo)
auxo=e5
l5 = LLDPDUGenericOrganisationSpecific(_type=e1,_length=e2,org_code=e3,subtype=e4,data=auxo)
auxa=f5[2:-1]
l6 = LLDPDUGenericOrganisationSpecific(_type=f1,_length=f2,org_code=f3,subtype=f4,data=auxa)
l7 = LLDPDUEndOfLLDPDU(_type=0,_length=0)
lldpu_layer = LLDPDU()
lldpu_layer = l1/l2/l3/l4/l5/l6/l7
pack = e/lldpu_layer
flag = False
sendp(pack,count=1, iface=ifa)
flag = True
lim = lim +1
with open(log,'a') as lf:
lf.write('read packet '+file+"\n")
I tried changing the data types, also fixed the data in the option "data" of
LLDPDUGenericOrganisationSpecific, but it did not work.
I hope I can have a packet with the right length so it reproduces exactly the non-crafted packet.

The problem was the encoding, it was wrong since I wrote the data in the data frame.
The solution was to encode with base64 BEFORE saving the information in the data frame, I used this explanation: Convert byte[] to base64 and ASCII in Python
That changed my data from b'`\xafE\x16\t\xa0#5\x02\x7f\xd5\p\xf7\x11A' to b'YK9FFgmgIzUCf9VccPcRQQ=='.
Then, when I had to put it in the field, I removed the b'' characters and then did the decoding, as said in the link.

Related

how to solv: gPRC with python,"the JSON object must be str, bytes or bytearray, not RepeatedScalarContainer"

This is my first question on this site, and my English is not so good.So,if there is any misunderstanding, please tell me. Thank you.
I am trying use gPRC to send a message ,which is defined as :
message PrepareMsg{
message Data{
string node_id = 1;
string vote = 2;
}
Data data = 1;
repeated string signature = 2;
}
My code for Cilent just like this:
1 def pre_prepare(self, block):
2 request = grpc_pb2.PrePrepareMsg()
3 request.data.node_id = self.node_id
4 request.data.block.CopyFrom(block)
5 a = request.data.SerializeToString()
6 temp_sign = signing(self.signer, a)
7 for i in temp_sign:
8 request.signature.append(hex(i))
9 self_node = set()
10 self_node.add(p2p.SELF_IP_PORT)
11 print(self_node)
12 nodes = set(p2p.Node.get_nodes_list()) - self_node
13 print("print nodes in broadcast:")
14 print(nodes)
15 for i in nodes:
16 channel = grpc.insecure_channel(i)
17 stub = grpc_pb2_grpc.ConsensusStub(channel)
18 try:
19 response = stub.PrePrepare(request)
20 print(response.Result)
21 except Exception as e:
22 print("get except: %s" % str(e))
I find there is a error :"Exception calling application: the JSON object must be str, bytes or bytearray, not RepeatedScalarContainer"
I don't know why it happened.

Read data from a DDSU666 using RS485

I have tried my luck with these codes to read the data from the DDSU666-H and it seems that I am able to read data, but I don't know what to do with it. In theory it is a list of data, but I am not able to understand what I am receiving or how to translate it into something I can use
import serial # import the module
def banner_bottom():
print(' +-------------------------------------------+')
print(' | SPACE |')
print(' +-------------------------------------------+')
COM_Port = serial.Serial('COM3')
COM_Port.baudrate = 9600 # set Baud rate
COM_Port.bytesize = 8 # Number of data bits = 8
COM_Port.parity = 'N' # No parity
COM_Port.stopbits = 1 # Number of Stop bits = 1
COM_Port.setRTS(1) #RTS=1,~RTS=0 so ~RE=0,Receive mode enabled for MAX485
COM_Port.setDTR(1) #DTR=1,~DTR=0 so DE=0,(In FT232 RTS and DTR pins are inverted)
#~RE and DE LED's on USB2SERIAL board will be off
RxedData = COM_Port.readline()
print(' ',RxedData, '\n')
COM_Port.close() # Close the Serial port
banner_bottom()# Display the bottom banner
Output:
b'\x7f~\xbb\xff\xfb\xe3=\x7f~_cuI_\x0e\x7f~\xbb\xff\xfb\xe3=\x7f~_]\xd3V\'\t\x7f~\xbb\xff\xfb\xe3=\x7f~__\x07\xf5tU\x7f~\xbb\xff\xfb\xe3=\x7f~_[y\x8d\xba\x00\x7f~\xbb\xff\xfb\xe3=\x7f~_YsGe\x18\x7f~\xbb\xff\xfb\xe3=\x7f~_Y\xe3\x06n\x16\x7f~\xbb\xff\xfb\xe3=\x7f~__O]I\x1d\x7f~\xbb\xff\xfb\xe3=\x7f~_ao\xff\xf0\x05\x7f~\xbb\xff\xfb\xe3=\x7f~_co-O\x10\x7f~\xbb\xff\xfb\xe3=\x7f~__\x15\x117\x03\x7f~\xbb\xff\xfb\xe3=\x7f~__!-\xc9/\x7f~\xbb\xff\xfb\xe3=\x7f~__}\xed|\x00\x7f~\xbb\xff\xfb\xe3=\x7f~_c\xb7+\xda\x00\x7f~\xbb\xff\xfb\xe3=\x7f~_e\x8f"U\x01\x7f~\xfd\xff\xfb]\x1a\x7f~_W\xaf\x08\x975\x00\x7f~\xfd\xff\xfb]\x1a\x7f~_W\xaf\x08\x975\x00\x7f~\xfd\xff\xfb]\x1a\x7f~_W\xaf\x08\x975\x00\x7f~\xbb\xff\xfb\xe3=\x7f~_]\xd3V\'\t\x7f~\xbb\xff\xfb\xe3=\x7f~__\xd9\xadb\x08\x7f~\xbb\xff\xfb\xe3=\x7f~__\xc5[P\x05\x7f~\xbb\xff\xfb\xe3=\x7f~__\x91\xfef\x00\x7f~\xbb\xff\xfb\xe3=\x7f~_c3\xb3T\x0f\x7f~\xbb\xff\xfb\xe3=\x7f~_e\xbd\x01\xb0\x03\x7f~\xbb\xff\xfb\xe3=\x7f~_e?y\x84\x19\x7f~\xbb\xff\xfb\xe3=\x7f~_\xe349\xac\n'
Code 2:
#!/usr/bin/env python3
import serial
port = 'COM3'
ComPort = serial.Serial(port)
ComPort.baudrate = 9600
ComPort.bitesize = 8
ComPort.parity = 'N'
ComPort.stopbits = 1
dataIn=ComPort.read(6)
print(dataIn)
ComPort.close()
Ouput:
b'\x7f~\xbb\xff\xfb\xe3'
I've tried to translate the output into something I can understand, but I haven't been able to see anything either.
binary_data = b'\x7f~\xbb\xff\xfb\xe3'
aa = binary_data.hex()
print(aa)
#OUT: 7f7ebbfffbe3
bb = ''.join(['%02x' % b for b in binary_data])
print(bb)
#OUT: 7f7ebbfffbe3
s = binary_data.decode('cp855')
print(s)
#OUT:~╗ чÑ
What can I try to resolve this?

pi won't read values from MCP3424

when I try to read data from a MCP3424 ADC, I get unexpected, wrong results. I know the device is connected, butthe results I'm reading are wrong
I write to channels 3 and 4 of the ADC. When I read the result back, the data in the config register doesn't match what I programmed
import smbus
import time
# Get I2C bus
bus = smbus.SMBus(1)
# I2C address of the device
MCP3425_DEFAULT_ADDRESS = 0x68
# MCP3425 Configuration Command Set
MCP3425_CMD_NEW_CNVRSN = 0x80 # Initiate a new conversion(One-Shot Conversion mode only)
MCP3425_CMD_MODE_CONT = 0x10 # Continuous Conversion Mode
MCP3425_CMD_MODE_ONESHOT = 0x00 # One-Shot Conversion Mode
MCP3425_CMD_SPS_240 = 0x00 # 240 SPS (12-bit)
MCP3425_CMD_SPS_60 = 0x04 # 60 SPS (14-bit)
MCP3425_CMD_SPS_15 = 0x08 # 15 SPS (16-bit)
MCP3425_CMD_GAIN_1 = 0x00 # PGA Gain = 1V/V
MCP3425_CMD_GAIN_2 = 0x01 # PGA Gain = 2V/V
MCP3425_CMD_GAIN_4 = 0x02 # PGA Gain = 4V/V
MCP3425_CMD_GAIN_8 = 0x03 # PGA Gain = 8V/V
MCP3425_CMD_READ_CNVRSN = 0x00 # Read Conversion Result Data
MCP3425_CMD_CH4 =0x60
MCP3425_CMD_CH3 =0x40
class MCP3425():
def __init__(self):
self.config_command()
def config_command(self):
"""Select the Configuration Command from the given provided values"""
CONFIG_CMD4 = (MCP3425_CMD_CH4| MCP3425_CMD_MODE_CONT | MCP3425_CMD_SPS_60 | MCP3425_CMD_GAIN_2)
bus.write_byte(MCP3425_DEFAULT_ADDRESS, CONFIG_CMD4)
CONFIG_CMD3 = (MCP3425_CMD_CH3| MCP3425_CMD_MODE_CONT | MCP3425_CMD_SPS_240 | MCP3425_CMD_GAIN_1)
bus.write_byte(MCP3425_DEFAULT_ADDRESS, CONFIG_CMD3)
print ('-C-', CONFIG_CMD4, CONFIG_CMD3)
def read_adc(self, channel):
"""Read data back from MCP3425_CMD_READ_CNVRSN(0x00), 2 bytes
raw_adc MSB, raw_adc LSB"""
data = bus.read_i2c_block_data(MCP3425_DEFAULT_ADDRESS, (MCP3425_CMD_READ_CNVRSN | channel), 3)
print (channel, data)
# Convert the data to 12-bits
raw_adc = ((data[0] & 0x0F) * 256) + data[1]
if raw_adc > 2047 :
raw_adc -= 4095
return {'r' : raw_adc}
#from MCP3425 import MCP3425
mcp3425 = MCP3425()
while True :
adc = mcp3425.read_adc(MCP3425_CMD_CH4)
print ("Digital Value of Analog Input 4: %d "%(adc['r']))
adc = mcp3425.read_adc(MCP3425_CMD_CH3)
print ("Digital Value of Analog Input 3: %d "%(adc['r']))
print (" ********************************* ")
time.sleep(0.8)
I write 117 (01110101)to channel 4, and 80 (01010000) to channel 3 config registers. Which means for both channels I should get 3 bytes back: 2 data bytes and one config register byte
this is the printout I'm getting, no values read (Ch4+ is connected to voltage divider (2.5v), Ch4- and Ch3- are connected to ground, Ch3+ is floating) and byte 3 is just the address, not the Config register
-C- 117 80
96 [0, 0, 96]
Digital Value of Analog Input 4: 0
64 [0, 0, 64]
Digital Value of Analog Input 3: 0
*********************************
now it took some time but I found the issue.
The trick was that the MCP3434 is not a 4-channel ADC, but a single ADC with an 4-input multiplexer. Once I realized that, the schematic from the datasheet was obvious. It is just not explained very well in the description on how to handle dataflow on the I2C bus.
So you can not configure two ADC's to measure in parallel but when you need to read more channels you have to
1) configure/start channel 1
2) read data
3) configure/start channel 2
4) read data
the read data step is thus channel independant.

How can I send with 'struct.pack' type over Modbus TCP?

I want to send packet over Modbus TCP. I want to use:
But I can not send this way how can I send this packet? (I don't know something will be)
req = struct.pack(
'Something', transaction, identifier, length, unitid, func_code, reg_addr
)
These are my variables:
transaction=0x01
identifier=0x00
length=[0x00,0x06]
unitid=0x01
func_code=0x03
reg_addr=[0x13,0x14,0x15]
At first you can use pymodbus library with very features.
Also struct.pack() not support a list as argument.
0001 0000 0006 11 03 006B 0003 is a standard example of Modbus-TCP packet which contained:
0001: Transaction Identifier
0000: Protocol Identifier
0006: Message Length (6 bytes to follow)
11: The Unit Identifier (17 = 11 hex)
03: The Function Code (read Analog Output Holding Registers)
006B: The Data Address of the first register requested. (40108-40001 = 107 =6B hex)
0003: The total number of registers requested. (read 3 registers 40108 to 40110)
Reference
Thus, you can create a Modbus-TCP packet with the above example:
import struct
transaction = 0x0001
identifier = 0x0000
length = 0x0006
unitid = 0x11
fcode = 0x03 # Holding register fcode.
reg_addr = 0x006B # Register address.
count = 0x0003 # Read three register.
total_pack_string = '0x{:04x}{:04x}{:04x}{:02x}{:02x}{:04x}{:04x}'.format(
transaction, identifier, length, unitid, fcode, reg_addr, count
)
total_pack_hex = hex(int(total_pack_string, 16))
'''Or with using pack method.'''
pack_ = struct.pack(
'>HHHBBHH', transaction, identifier, length, unitid, fcode, reg_addr, count
)
# Then send the pack_ or total_pack_hex using a TCP-Socket.
[NOTE]:
transaction is 2Byte == Short == H
identifier is 2Byte == Short == H
length is 2Byte == Short == H
unitid is 1Byte == B
fcode is 1Byte == B
reg_addr is 2Byte == Short == H
count is 2Byte == Short == H
B is unsigned byte
H is unsigned short
Thus, the format will be like this >HHHBBHH
Using pymodbus equivalent:
from pymodbus.client.sync import ModbusTcpClient
unitid = 0x11
fcode = 0x03 # Holding register fcode.
reg_addr = 0x006B # Register address.
count = 0x0003 # Read three register.
cli = ModbusTcpClient('127.0.0.1', port=502)
if cli.connect():
res = cli.read_holding_registers(reg_addr, count=count, unit=unitid)
if not res.isError():
print(res.registers)
else:
print('There is an error.')
cli.close()
else:
print('Error in connection.')

Scapy: How to access a Custom Layer

I am trying to understand how to add a custom dissector in Scapy. I am using Python 3.4 and Scapy3 if that has any bearing on the result.
I have a stupid class, and the packet.show2() command correctly renders the nested packet. But I can not access the new Layers field values.
Scary Class and bind_layer follows...
from scapy.all import *
#Create simple Class
class DUMBO(Packet):
fields_desc = [
ShortField('ears',0),
ShortField('legs',0),
ShortField('trunk',0)
]
#Inform TCP that ports 9898 are this protocol
bind_layers(TCP, DUMBO, sport=9898, dport=9898)
I make a packet like this
#Make a Packet
pack=IP()/TCP(sport=9898, dport=9898)/Raw(load=b'\x00\x02\x00\x04\x00\x01')
Looking at the Packet I have created using ls yields
version : BitField = 4 (4)
ihl : BitField = None (None)
tos : XByteField = 0 (0)
len : ShortField = None (None)
id : ShortField = 1 (1)
flags : FlagsField = 0 (0)
frag : BitField = 0 (0)
ttl : ByteField = 64 (64)
proto : ByteEnumField = 6 (0)
chksum : XShortField = None (None)
src : Emph = '127.0.0.1' (None)
dst : Emph = '127.0.0.1' ('127.0.0.1')
options : PacketListField = [] ([])
--
sport : ShortEnumField = 9898 (20)
dport : ShortEnumField = 9898 (80)
seq : IntField = 0 (0)
ack : IntField = 0 (0)
dataofs : BitField = None (None)
reserved : BitField = 0 (0)
flags : FlagsField = 2 (2)
window : ShortField = 8192 (8192)
chksum : XShortField = None (None)
urgptr : ShortField = 0 (0)
options : TCPOptionsField = {} ({})
--
load : StrField = b'\x00\x02\x00\x04\x00\x01' (b'')
And display it using Show2 it all looks good
pack.show2()
###[ IP ]###
version = 4
ihl = 5
tos = 0x0
len = 46
id = 1
flags =
frag = 0
ttl = 64
proto = tcp
chksum = 0x7cc7
src = 127.0.0.1
dst = 127.0.0.1
\options \
###[ TCP ]###
sport = monkeycom
dport = monkeycom
seq = 0
ack = 0
dataofs = 5
reserved = 0
flags = S
window = 8192
chksum = 0x447f
urgptr = 0
options = []
###[ DUMBO ]###
ears = 2
legs = 4
trunk = 1
I now want to access the DUMBO Layer fields
But
PACK[DUMBO].ears
Is not correct - as the packet when displayed as pack.show() still has the Payload as Raw....
What am I missing ??
Ok - This is my solution....
pack=IP()/TCP(sport=19898, dport=19898)/Raw(load=b'\x00\x02\x00\x04\x00\x01')
#Cast this packet back
pack=IP(bytes(pack))
pack.show2()
pack.show()
if DUMBO in pack:
print('Elephant in the house')
print('Ears -> {}'.format(pack[DUMBO].ears))
If anyone else can improve on this I would be happy on seeing the solution.
Note: I'm just getting started with Scapy, so I can't promise this is the correct/only way to go.
As per Documentation: Add new protocols to Scapy, put the code with the protocol definition in a seperate python file. Make sure you also set the required headers. Then place that file either in scapy/layers or scapy/contrib.
After that, the protocol can be loaded with load_layer(...) or load_contrib(...) where you plan on using it.
For DUMBO we'll go with contrib.
dumbo.py:
# scapy.contrib.description = Dumbo the elephant
# scapy.contrib.status = loads
from scapy.packet import Packet, bind_layers
from scapy.fields import ShortField
from scapy.layers.inet import TCP
#Create simple Class
class DUMBO(Packet):
fields_desc = [
ShortField('ears',0),
ShortField('legs',0),
ShortField('trunk',0)
]
#Inform TCP that ports 9898 are this protocol
bind_layers(TCP, DUMBO, sport=9898, dport=9898)
Now let's use it:
$ scapy
>>> load_contrib("dumbo")
>>> pack1=IP()/TCP(sport=9898, dport=9898)/DUMBO(b'\x00\x02\x00\x04\x00\x01')
>>> pack2=IP()/TCP(sport=9898, dport=9898)/DUMBO(ears=2, legs=4, trunk=1)
>>> pack1
<IP frag=0 proto=tcp |<TCP sport=9898 dport=9898 |<DUMBO ears=2 legs=4 trunk=1 |>>>
>>> pack2
<IP frag=0 proto=tcp |<TCP sport=9898 dport=9898 |<DUMBO ears=2 legs=4 trunk=1 |>>>
>>> pack1[DUMBO].ears
2
>>> pack2[DUMBO].ears
2
Hope this helps somebody who stumbles upon this question.
Versions used: Python v3.8.5 ; Scapy v2.4.5

Categories

Resources