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

时间:2015-11-15 18:50:08

标签: python sockets tcp scapy raw-sockets

我有一个客户端发送带有自定义图层的数据包"预订"用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 的东西来检索该字段的值。有可能吗?

EDIT 我达到了这一点: 我正在通过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'

显然,“预留”图层无法识别并解释为RAW。如何构建与传输的数据包相同的数据包?

1 个答案:

答案 0 :(得分:2)

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

在你的情况下:

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

请注意,您还可以使用bind_layers()绑定您的图层以进行scapys autodissect / payload guess,以使其与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字节流时使用。

Raw Socket:

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