5

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.

Neuron
  • 5,141
  • 5
  • 38
  • 59
Noah Koster
  • 165
  • 1
  • 3
  • 8
  • Interesting question, I can't really help, but maybe this question is relevant: http://stackoverflow.com/questions/6329583/how-to-reliably-generate-ethernet-frame-errors-in-software – Daniel Figueroa Sep 01 '12 at 16:35
  • Patience is a virtue. Also keep in mind that the easier you make your question to read, the more likely someone can quickly understand the nature of your problem and propose a useful solution (hint: correct capitalisation and paragraph breaks help a lot) – talonmies Sep 01 '12 at 16:50
  • 1
    Other examples use AF_PACKET instead of AF_INET, you might want to try it if you are running Linux, since it appears to be Linux specific. – Roland Smith Sep 01 '12 at 17:15
  • thanks guys, i havent tried it on linux yet but i guess i could. il get back to you if it works on linux. i have a mac osx btw with windows 7, xp and debian. il add linux right now... o and im sry for not being patient. – Noah Koster Sep 01 '12 at 17:19
  • 1
    @NoahKoster: If you are really trying to send a raw ethernet frame, as your say in the title, why are you using an AF_INET socket bound to an IP address? Shouldn't you be using AF_PACKET, bound to an interface? – talonmies Sep 02 '12 at 12:32
  • its because mac osx doesnt support af_packet, i have a linux kernel though which i should boot up and does support it. its a bad computer though... so i think im gonna get linux in a virtual machine on my mac osx. i am way too lazy... – Noah Koster Sep 03 '12 at 14:57
  • Does this answer your question? [How Do I Use Raw Socket in Python?](https://stackoverflow.com/questions/1117958/how-do-i-use-raw-socket-in-python) – Rok Povsic Jun 24 '20 at 14:41
  • btw "Debian" *is* a Linux distro. – Esther May 20 '22 at 12:58

2 Answers2

7

Thanks to the commenters, 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 bound it to my nic and sent it. It worked.

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 knowledge it doesn't work in mac osx. idk about windows. if u have a mac use pycap or scapy, they work fine.

Neuron
  • 5,141
  • 5
  • 38
  • 59
Noah Koster
  • 165
  • 1
  • 3
  • 8
  • 1
    Thanks for sharing! Can you post an example that is sending a string or something? It's not clear how much "magic" is abstracted by your "packet" class. – Andrew Wagner May 13 '14 at 16:06
  • I couldn't post code here, so see below for a snipped of data that worked for me. – CyberFonic Oct 31 '16 at 08:53
0

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
Neuron
  • 5,141
  • 5
  • 38
  • 59