了解原始套接字包头

时间:2018-02-16 18:59:19

标签: python python-3.x sockets

我使用this code在Python中编写了一个套接字数据包嗅探器。

import socket, struct

# Setup socket object
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_UDP)
s.bind((socket.gethostbyname(socket.gethostname()), 0))
s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
s.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)

Id = 0
while (True):
    data = s.recvfrom(65565)
    packet = data[0]
    address = data[1]
    header = struct.unpack("!BBHHHBBHBBBBBBBB", packet[:20])

    if (header[6] == 6):
        protocol = "TCP"
    elif (header[6] == 17):
        protocol = "UDP"

    print("Number: ", Id, end="\t")
    print("Protocol: ", protocol, end="\t")
    print("Address: ", address, end="")
    print("Header: ", header)
    #print("Data: ", data)
    print()
    Id += 1
  1. 我知道我可以在数据变量(data [0])的索引0处找到接收器IP地址,但是在数据包中我会找到发件人的IP地址和端口号吗?
  2. 标题元组中的所有整数是什么意思?我知道header [6]是协议TCP / UDP,但其余的呢?

    标题:(69,0,61,1541,0,128,17,0,192,168,56,1,255,255,255,255)

1 个答案:

答案 0 :(得分:1)

IP标头有well-defined structureRFC。你决定用字节和短路解压缩它。一般来说,您希望将每个字段的大小与正确的数据类型相匹配。看一下正确的标题大小,您可以看到个别细分:

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |Version|  IHL  |Type of Service|          Total Length         |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |         Identification        |Flags|      Fragment Offset    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |  Time to Live |    Protocol   |         Header Checksum       |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                       Source Address                          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Destination Address                        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Options                    |    Padding    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

这可以通过编程方式完成:

struct.unpack('!BBHHHBBHII')
# alternatively:
struct.unpack('!BBHHHBBH4s4s')

我更喜欢后者,因为你可以很容易地将它转换为IP地址:

示例以太网标头:

0000   3c 4a 92 1f 04 00 74 c6 3b 8d 82 69 08 00 45 00  <J....t.;..i..E.
0010   00 3c 0a 24 40 00 40 06 23 76 0a 14 01 0d 01 01  .<.$@.@.#v......
0020   01 01 e7 7a 04 d2 a2 5e 0c d2 00 00 00 00 a0 02  ...z...^........
0030   72 10 0d 51 00 00 02 04 05 b4 04 02 08 0a 9c d4  r..Q............
0040   c0 c0 00 00 00 00 01 03 03 07                    ..........

packet[14:34]处存在20字节的IPv4标头。使用上述格式打开包装会产生以下结果:

>>> header = struct.unpack('!BBHHHBBH4s4s', packet[14:34])
>>> header
(69, 0, 60, 2596, 16384, 64, 6, 9078, b'\n\x14\x01\r', b'\x01\x01\x01\x01')

指数8和9分别是源IP和目标IP。因为它们是字节,我们可以将它们转换为int然后转换为str以获得字符串格式的IP:

# Note: Python 3 only
>>> ip_src = '.'.join(map(str, header[8]))  # 10.20.1.13
>>> ip_dst = '.'.join(map(str, header[9]))  # 1.1.1.1