Buringg 2022-07-04 15:15 采纳率: 14.3%
浏览 21
已结题

通过python socket构建raw包设置偏移位后无法发包

问题遇到的现象和发生背景

通过python 发送自定义的包,我想模拟一个分片的包,通过设置ip_frag_offset这个参数来发送那种分片的数据包,但是发现这个参数只能设置为0,如果我设置为其它正整数就无法发送数据包,设置为0是可以正常发包的,

问题相关代码,请勿粘贴截图
# -*- coding: utf-8 -*
'''
    A very simple raw socket implementation in Python
'''

import sys, socket
from struct import *

def carry_around_add(a, b):
    c = a + b
    return (c & 0xffff) + (c >> 16)

def checksum(msg):
    s = 0
    for i in range(0, len(msg), 2):
        w = (ord(msg[i]) << 8 ) + ord(msg[i+1])
        s = carry_around_add(s, w)
    return ~s & 0xffff

try:
    s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
except socket.error , msg:
    print ('Socket could not be created. Error Code : ' + str(msg[0]) + ' Message ' + msg[1])
    sys.exit()

ip_source = '10.0.2.15' #本机IP
ip_dest = '64.4.11.42'    #也可以用域名:socket.gethostbyname('www.microsoft.com')

#填写ip header
ip_ver = 4            # ipv4
ip_ihl = 5            # Header Length =5, 表示无options部分
ip_dscp = 1            # 以前叫tos,现在叫dscp
ip_total_len = 0        # left for kernel to fill
ip_id = 22222            # fragment相关,随便写个
ip_frag_offset = 0        # fragment相关
ip_ttl = 25            # *nix下TTL一般是255
ip_protocol = socket.IPPROTO_UDP    # 表示后面接的是udp数据
ip_checksum = 0            # left for kernel to fill
ip_saddr = socket.inet_pton(socket.AF_INET, ip_source)    # 两边的ip地址
ip_daddr = socket.inet_pton(socket.AF_INET, ip_dest)

ip_ver_ihl = (ip_ver << 4) + ip_ihl    # 俩4-bit数据合并成一个字节

# 按上面描述的结构,构建ip header。
ip_header = pack('!BBHHHBBH4s4s' , ip_ver_ihl, ip_dscp, ip_total_len, ip_id, ip_frag_offset, ip_ttl, ip_protocol, ip_checksum, ip_saddr, ip_daddr)


udp_sport = 1000    # source port
udp_dport = 80        # destination port
udp_seq = 19890604    # 32-bit sequence number,这里随便指定个
udp_ack_seq = 0        # 32-bit ACK number。这里不准备构建ack包,故设为0
udp_data_offset = 5    # 和ip header一样,没option field
# 下面是各种udp flags
udp_flag_urg = 0
udp_flag_ack = 0
udp_flag_psh = 0
udp_flag_rst = 0
udp_flag_syn = 1
udp_flag_fin = 0

udp_window_size = 3000
udp_checksum = 0
udp_urgent_ptr = 0

# 继续合并small fields
udp_offset_reserv = (udp_data_offset << 4)
udp_flags = udp_flag_fin + (udp_flag_syn << 1) + (udp_flag_rst << 2) + (udp_flag_psh <<3) + (udp_flag_ack << 4) + (udp_flag_urg << 5)

# 按上面描述的结构,构建udp header。
udp_header = pack('!HHLLBBHHH' , udp_sport, udp_dport, udp_seq, udp_ack_seq, udp_offset_reserv, udp_flags, udp_window_size, udp_checksum, udp_urgent_ptr)

# 写点东西作为data部分(可选)
payload_data = 'qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq'
# 构建pseudo ip header
psh_saddr = ip_saddr
psh_daddr = ip_daddr
psh_reserved = 0
psh_protocol = ip_protocol
psh_udp_len = len(udp_header) + len(payload_data)
psh = pack('!4s4sBBH', psh_saddr, psh_daddr, psh_reserved, psh_protocol, psh_udp_len)

# 创建最终用于checksum的内容
chk = psh + udp_header + payload_data

# 必要时追加1字节的padding
if len(chk) % 2 != 0:
    chk += '\0'

udp_checksum = checksum(chk)

# 重新构建udp header,把checksum结果填进去
udp_header = pack('!HHLLBBHHH' , udp_sport, udp_dport, udp_seq, udp_ack_seq, udp_offset_reserv, udp_flags, udp_window_size, udp_checksum, udp_urgent_ptr)

# 最终的udp/ip packet!
packet = ip_header + udp_header + payload_data
# 发送出去
s.sendto(packet, (ip_dest, 0))

运行结果及报错内容

ip_frag_offset设置为非0后抓不到包也没有报错。

我的解答思路和尝试过的方法
我想要达到的结果
  • 写回答

1条回答 默认 最新

  • 於黾 2022-07-04 15:28
    关注

    你写的是应用层的协议
    底层怎么分片不是你这里要管的事情
    你可以把一个数组拆成2次发送
    但是你没法保证接收到之后是需要接收两次才能接收全
    对方有可能一次就接收到全部的数据,也有可能分三次接收到

    评论

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 7月9日
  • 创建了问题 7月4日

悬赏问题

  • ¥30 comfyui openpose报错
  • ¥20 Wpf Datarid单元格闪烁效果的实现
  • ¥15 图像分割、图像边缘提取
  • ¥15 sqlserver执行存储过程报错
  • ¥100 nuxt、uniapp、ruoyi-vue 相关发布问题
  • ¥15 浮窗和全屏应用同时存在,全屏应用输入法无法弹出
  • ¥100 matlab2009 32位一直初始化
  • ¥15 Expected type 'str | PathLike[str]…… bytes' instead
  • ¥15 三极管电路求解,已知电阻电压和三级关放大倍数
  • ¥15 ADS时域 连续相位观察方法