问题遇到的现象和发生背景
通过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后抓不到包也没有报错。