简体   繁体   English

如何在 python 中发送原始以太网帧?

[英]How do I send a raw ethernet frame in python?

I need to have a project done in a few days, its a basic client and server interface.我需要在几天内完成一个项目,它是一个基本的客户端和服务器接口。 The catch is that it needs to be all raw sockets.问题是它必须是所有原始套接字。 I have no problem with creating that, I am just stuck on sending the packets.我创建它没有问题,我只是坚持发送数据包。

First I tried to bind it to an interface 'en1' but it keeps giving me an error nodename not known .首先,我尝试将其绑定到接口“en1” ,但它一直给我一个错误nodename not known When I bind it to my local ip address it works fine.当我将它绑定到我的本地 IP 地址时,它工作正常。 After completing this I created a raw packet class, its all in hex.完成此操作后,我创建了一个原始数据包类,全部为十六进制。 I then did a sendto call to send it on the wire.然后我做了一个 sendto 调用以通过网络发送它。

The problem is that when I capture the packet by using wireshark it shows up as being the payload of a ipv4 packet.问题是当我使用wireshark捕获数据包时,它显示为ipv4数据包的有效负载。 I don't want it to make the headers automatically, that is what my raw packet class was for anyway.我不希望它自动生成标题,这就是我的原始数据包类的用途。 Do you know of any way I can take out these headers?你知道我有什么办法可以取出这些标题吗?

Here is my code - only the raw function:这是我的代码 - 只有原始函数:

def raw():
    HOST = gethostbyname('192.168.1.10')

    s = socket(AF_INET, SOCK_RAW, IPPROTO_IP)
    s.bind((HOST, 0))

    s.setsockopt(IPPROTO_IP, IP_HDRINCL, 0) #no headers - it wont work!!

    pckt = packet("\x68\x65\x6c\x6c\x6f")
    netpacket = pckt.getpacket()

    print "Sending.. "
    print ""

    s.sendto(netpacket, ('192.168.1.1', 80))
    data = s.recv(4096)
    print data

And here is the captured packet with a hello at the end:这是捕获的数据包,最后带有一个hello

007f 2809 6da2 28cf daee 2156 0800 4500 004d 1bfc 0000 4000 db59 c0a8 010a c0a8 0101* 007f     

2809 6da2 28cf daee 2156 0800 4500 0036 2352 4000 4006 0000 c0a8 010a c0a8 0101 15c0 0050 

0000 0000 0000 0000 8010 813b 0000 68656c6c6f -hello

*This (the 0101 ) is the start of the payload even though it was supposed to be the start of the packet. *这( 0101 )是有效载荷的开始,即使它应该是数据包的开始。 Also I am not going to use any other modules, I have to use socket.另外我不会使用任何其他模块,我必须使用套接字。

thanks to the comments for this question, i managed to get a connection going with a server.感谢对这个问题的评论,我设法与服务器建立了连接。 all it took was changing the address family to af_packet in linux.只需将地址族更改为 linux 中的 af_packet 即可。 then i binded it to my nic and sent it.然后我将它绑定到我的网卡并发送。 it worked.有效。 thanks for the help people!感谢人们的帮助! here is some example code:这是一些示例代码:

s = socket(AF_PACKET, SOCK_RAW)
s.bind(("en1", 0))
pckt = packet() #my class that initializes the raw hex
data = pckt.getpacket()
s.send(data)
message = s.recv(4096)
print s
print s.decode('hex')

It needs to be in linux or debian.它需要在linux或debian中。 to my knowldege it doesnt work in mac osx.据我所知,它在 mac osx 中不起作用。 idk about windows.对窗户不以为然。 if u have a mac use pycap or scapy, they work fine.如果你有一个使用 pycap 或 scapy 的 mac,它们可以正常工作。

In answer to your question Andrew, here's an example:为了回答你的问题安德鲁,这里有一个例子:

This answer helped me get WoL working.这个答案帮助我让 WoL 工作。 In this case the data is:在这种情况下,数据是:

preamble = bytearray((0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF))
MAC = bytearray((0x00, 0x14, 0x85, 0xa4, 0x73, 0xce))
data = PREAMBLE + 16*MAC

This Python script allows to send a raw packet written in hex in a separate file (bytes hex representation separated by space or newline).此 Python 脚本允许在单独的文件中发送以十六进制编写的原始数据包(字节十六进制表示由空格或换行符分隔)。
Usage is script_name.py interface packet_file用法是script_name.py interface packet_file

#!/bin/python

ETH_P_ALL = 0x0003
import socket
import sys

if __name__ == "__main__":
  interface = sys.argv[1]
  filename = sys.argv[2]

  with open(filename, 'r') as file:
    hexlist = [int(x, 16) for x in file.read().split()]

  packet = bytearray(hexlist)

  with socket.socket(socket.AF_PACKET, socket.SOCK_RAW) as rs:
    rs.bind((interface, ETH_P_ALL))
    sentbytes = rs.send(packet)

  print("Sent packet of length %d bytes" % sentbytes)

Packet file example (ARP Request who-has 192.168.1.2 tell 192.168.1.1):数据包文件示例(ARP Request who-has 192.168.1.2 tell 192.168.1.1):

 ff ff ff ff ff ff
 00 11 22 33 44 55
 08 06
 00 01 08 00 06 04
 00 01
 00 11 22 33 44 55
 C0 A8 01 02
 00 00 00 00 00 00
 C0 A8 01 01
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

Note that because separator between hex bytes is spaces or new lines, it is easy to separate frames in the file, here the 3 first lines are the Ether frame, then the next lines are the ARP frame and the last line is the padding to reach 60 bytes in length.请注意,由于十六进制字节之间的分隔符是空格或换行符,因此文件中的帧很容易分隔,这里前 3 行是 Ether 帧,接下来是 ARP 帧,最后一行是要到达的填充长度为 60 字节。

Usage example with this file named my arp-packet.dat and the python script named send_raw_packet.py :此文件名为my arp-packet.dat和 python 脚本名为send_raw_packet.py的用法示例:

host:~$ send_raw_packet.py eth0 arp_packet.dat
Sent packet of length 60 bytes

And capturing with tcpdump shows the packet was sent:使用 tcpdump 捕获显示数据包已发送:

host:~$ tcpdump -i eth0 -Q out -tevvv -XX arp
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
00:11:22:33:44:55 (oui Unknown) > Broadcast, ethertype ARP (0x0806), length 60: Ethernet (len 6), IPv4 (len 4), Request who-has 192.168.1.1 tell 192.168.1.2, length 46
0x0000:  ffff ffff ffff 0011 2233 4455 0806 0001  ........"3DU....
0x0010:  0800 0604 0001 0011 2233 4455 c0a8 0102  ........"3DU....
0x0020:  0000 0000 0000 c0a8 0101 0000 0000 0000  ................
0x0030:  0000 0000 0000 0000 0000 0000            ............
1 packet captured
1 packet received by filter
0 packets dropped by kernel

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM