简体   繁体   中英

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 . When I bind it to my local ip address it works fine. 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.

The problem is that when I capture the packet by using wireshark it shows up as being the payload of a ipv4 packet. 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:

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. 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. 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. to my knowldege it doesnt work in mac osx. idk about windows. if u have a mac use pycap or scapy, they work fine.

In answer to your question Andrew, here's an example:

This answer helped me get WoL working. 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).
Usage is 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):

 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.

Usage example with this file named my arp-packet.dat and the python script named 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:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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