运用Raw Socket进行以太网帧解析

RAW SOCKET

RAW Socket提供了一种方法来绕过整个网络堆栈遍历,并直接将以太网帧输送到一个应用程序的方法。

(跳过网络层和传输层的过滤解析,因而可以直接处理新的或是自定义的数据包格式)


常用创建RAW Socket格式的方法:AF_PACKET和PF_SOCKET。AF_PACKET用于win和mac系统。本篇介绍基于Linux的PF_PACKET创建方法。


基于PF_PACKET的PF_SOCKET

使用socket模块读取收到的包

对进行解释和分析


>>> import socket
>>> import struct 
>>> import binascii 
>>> 
>>> rawSocket = socket.socket(socket.PF_PACKET,socket.SOCK_RAW,socket.htons(0x0800))
>>> pkt = rawSocket.recvfrom(2048) 
>>> ethernetHeader = pkt[0][0:14] 
>>> ethernetHeader
'\x90\xb1\x1cZ\xa8\x89p\xf9mYF\x9d\x08\x00'
>>> binascii.hexlify(eth_hdr[0]) 
'90b11c5aa889'
>>> binascii.hexlify(eth_hdr[1]) 
'70f96d59469d'
>>> binascii.hexlify(eth_hdr[2])
'0800'
>>> ipHeader = pkt[0][14:34] 
>>> ip_hdr = struct.unpack("!12s4s4s",ipHeader) 
>>> ip_hdr
('E\x00\x00(U\xe4@\x00~\x06\x91\xbe', '\xc0\xa8d\x9a', '\xc0\xa8/B')
>>> socket.inet_ntoa(ip_hdr[1])
'192.168.100.154'
>>> socket.inet_ntoa(ip_hdr[2])
'192.168.47.66'
>>> tcpHeader = pkt[0][34:54]


由此进行数据包解析


由PF_PACKET进行自定义二层发包和收包(要求二层直连,两台测试机没有直连害我搞了一下午= =),简易代码

发送端

import struct
import socket

s= socket.socket(socket.PF_PACKET, socket.SOCK_RAW, socket.htons(0x0901))
s.bind(("eth1", 0))

#dst_addr = "\x90\xb1\x1c\x5a\xa8\x89"
dst_addr = "\x00\x0c\x29\x89\xaf\x38"
src_addr = "\x00\x0c\x29\xb6\xe5\xb7"

ethtype = "\x09\x01"

packet = struct.pack("!6s6sH", dst_addr, src_addr, 0x0901)

s.send(packet + "hello!")

接收端

import socket
import struct
import binascii

socket1 = socket.socket(socket.PF_PACKET, socket.SOCK_RAW, socket.htons(0x0901))

while True:
        pkt = socket1.recvfrom(2048)
        eth_header =  pkt[0][0:14]
        eth_hdr = struct.unpack("!6s6sH",eth_header)
        print repr(eth_hdr[0])
        type = eth_hdr[2]
        if( type == 0x0901):
                print("get 0x0901")

print("end")

--------------------分割线------------------------


发送端完整版

import socket
import struct
import binascii

def set_mac(hexstring):
        mac_addr=[]
        for i in xrange(0, len(hexstring)/2):
                int_c = int(hexstring[i*2:i*2+2],16)
                mac_addr.append(int_c)
        return mac_addr

def packed(dmac, smac, ethtype):
        packed = b""
        i =0
        for value in dmac:
                packed += struct.pack("!B", value)
        for value in smac:
                packed += struct.pack("!B", value)

        packed += struct.pack("!H", ethtype)
        return packed

socket2 = socket.socket(socket.AF_PACKET, socket.SOCK_RAW)
socket2.bind(('eth1', 0))
data = b""
d_mac = "000c2989af38"
s_mac = "000c29b6e5b7"
dmac = set_mac(d_mac)
smac = set_mac(s_mac)
ethtype = 0x0901
pack_res = packed(dmac, smac, ethtype)
data += pack_res
try:
        socket2.send(data)
        print('ok')
except:
        raise Exception("send failed")



你可能感兴趣的:(运用Raw Socket进行以太网帧解析)