在 Python 的 tcp 套接字中提取接收到的数据

Extract received data in a tcp socket in Python

我有一个客户端发送一个带有自定义层的数据包 "Reservation" 使用 Scapy

创建

Client.py

#!/usr/bin/env python

import socket
from scapy.all import *


class Reservation(Packet):
    name = "ReservationPacket"
    fields_desc=[ ShortField("id", 0),
            BitField("type",None, 0),
            X3BytesField("update", 0),
            ByteField("rssiap", 0)]


pkt = IP(len=16384, src='192.168.240.5', dst='192.168.240.198',
id=RandShort(), ttl=2)/TCP(sport=5005,
dport=5005, flags="S", window=200,
options=[('MSS', 1460), ('WScale',    2)])/Reservation(id=11)/"HELLO"

spkt = bytes(pkt)
spkt += '\x00'*20

s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
s.setsockopt(socket.SOL_IP, socket.IP_HDRINCL, 1)

s.sendto(spkt, ('192.168.240.198', 5005))

s.close()

数据包发送和接收正确

如何访问数据包的特定字段?我如何解释接收到的数据?我想使用类似于 spkt.id 的东西来检索该字段的值。有可能吗?

编辑 我已经达到了这一点: 我正在通过 tcp 套接字发送 pcaket。它具有以下结构:

###[ IP ]###
  version   = 4
  ihl       = None
  tos       = 0x0
  len       = 16384
  id        = <RandShort>
  flags     = 
  frag      = 0
  ttl       = 2
  proto     = tcp
  chksum    = None
  src       = 192.168.240.5
  dst       = 192.168.240.1
  \options   \
###[ TCP ]###
     sport     = 5005
     dport     = 5005
     seq       = 0
     ack       = 0
     dataofs   = None
     reserved  = 0
     flags     = S
     window    = 200
     chksum    = None
     urgptr    = 0
     options   = [('MSS', 1460), ('WScale', 2)]
###[ ReservationPacket ]###
     id        = 9
     type      = None
     update    = 0x0
     rssiap    = 0 
###[ Raw ]###
      load      = 'PROVA'

其中 ReservationPacket 是自定义层。 数据包已收到并带有

    data = conn.recv(BUFFER_SIZE)
    if not data: break
          print "received data:", data
          by = str.encode(data)             
          pkt_hex = by.encode('hex')
          hexdump(by)
          container = IP(data)
          container.show()

我填充容器包,定义为

container = IP()/TCP()/Reservation()

的输出
container.show()

###[ IP ]###
version   = 4L
ihl       = 5L
tos       = 0x0
len       = 16384
id        = 56856
flags     = 
frag      = 0L
ttl       = 2
proto     = tcp
chksum    = 0x3987
src       = 192.168.240.5
dst       = 192.168.240.1
\options   \
###[ TCP ]###
 sport     = 5005
 dport     = 5005
 seq       = 0
 ack       = 0
 dataofs   = 7L
 reserved  = 0L
 flags     = S
 window    = 200
 chksum    = 0xd962
 urgptr    = 0
 options   = [('MSS', 1460), ('WScale', 2), ('EOL', None)]
###[ Raw ]###
    load      = '\x00\t\x00\x00\x00\x00PROVA'

显然,Reservation 层未被识别和解释为 RAW。如何构建与传输的数据包相同的数据包?

您可以使用 s=str(packet) 在 scapy 2 中序列化数据包,并使用 packet=Layer(s) 强制将字节流反序列化为 Layer.

你的情况:

rdata = sock.recv(8192)
layer = Reservation(rdata)
layer.show()
print layer.id

请注意,您还可以为 scapys autodissect/payload 猜测绑定层 bind_layers() 以使其与 sniff() 一起工作或剖析 tcp/Reservation 字节流(tcp 数据包与保留负载)。以下行将 TCP.dport=5005 绑定到 Reservation.

bind_layers(TCP, Reservation, dport=5005)

更新:具体回答你的问题。

您不必关心 IP/TCP 层,因为这一切都在套接字内处理。 socket.recv 接收到的数据是 TCP 的有效负载,因此您所要做的就是强制 scapy 将接收到的 data 反序列化为 Reservation.

TCP 套接字:

data=[]
while True:
    chunk = conn.recv(BUFFER_SIZE)
    if not chunk: 
        break
    print "received data:", chunk
    data.append(chunk)
layer = Reservation(''.join(data))
layer.show()
print layer.id

此外,您可以指示 scapy 尝试根据简单规则自动剖析您的图层,例如TCP.dport==5005 调用 bind_layers()。这样它也可以与 sniff 一起使用,或者当您收到完整的 IP/TCP/Reservation/Raw 字节流时。

原始套接字:

bind_layers(TCP, Reservation, dport=5005) # bind Reservation as nextlayer to TCP.dport=5005
# ...
data, peer = s.recvfrom(BUFFER_SIZE)
print "received data:", peer, repr(data)
layer = IP(data)                # dissection automagic based on rules registered with bind_layers
layer.show()
print layer[Reservation].id