本文参考了博文:https://blog.csdn.net/jeanphorn/article/details/45599469
先对博文代码进行一个简单的解析。
import socket
import struct
#0x0800似乎对不同的包来说并不影响
rawSocket = socket.socket(socket.PF_PACKET, socket.SOCK_RAW, socket.htons(0x0800))
#"eth0"为要发包的网卡,0x0800似乎对不同的包来说并不影响
rawSocket.bind(("eth0",socket.htons(0x0800)))
#6s代表6B的字符串,其他类推
packet=struct.pack("!6s6s2s",b'\xaa\xaa\xaa\xaa\xaa\xaa',b'\xbb\xbb\xbb\xbb\xbb\xbb',b'\x08\x00')
rawSocket.send(packet + "hello, there.")
如此便能发送一个简单的链路层包了。在链路层发包的好处包的payload从网络层开始都可以随意自定义。
例如我的packet构造为:
import socket
import struct
#0x0800似乎对不同的包来说并不影响
rawSocket = socket.socket(socket.PF_PACKET, socket.SOCK_RAW, socket.htons(0x0800))
#"eth0"为要发包的网卡,0x0800似乎对不同的包来说并不影响
rawSocket.bind(("eth0",socket.htons(0x0800)))
src_mac = b'\xaa\xaa\xaa\xaa\xaa\xaa'
dst_mac = b'\xbb\xbb\xbb\xbb\xbb\xbb'
eth_type = b'\x86\xdd'
version = 6
traffic_class = 0
flowlabel_1 = 0 # first 4 bit of flowlabel
flowlabel_2 = 0 # last 16 bit of flowlabel
total_len = 32
next_header = 153
hop_limit = 253
version_traffic_flow = (version << 12) + (traffic_class << 4) + flowlabel_1
src_ipv6 = socket.inet_pton(socket.AF_INET6, "fe80::49e8:4a9a:faf1:2379")
dst_ipv6 = socket.inet_pton(socket.AF_INET6, "ff02::1:ff0f:cd7d")
#H is 2 Bytes, B is 1 Byte
#ipv6_header here is 40 Bytes
ipv6_header = struct.pack('!6s6s2sHHHBB16s16s', src_mac, dst_mac, eth_type,
version_traffic_flow, flowlabel_2,
total_len, next_header, hop_limit, src_ipv6, dst_ipv6)
rawSocket.send(ipv6_header + "hello,here.")
该packet构造了一个ipv6包头(长度并不正确,用户根据需要自行计算填充),标识ipv6的字段在于eth_type为0x86dd。
构造packet的关键在于正确使用struct.pack()函数,可以参考这篇博文:
https://blog.csdn.net/weiwangchao_/article/details/80395941