Skip to content

Commit 87c7b9b

Browse files
committed
Initial commit
1 parent 419dd1a commit 87c7b9b

5 files changed

Lines changed: 209 additions & 0 deletions

File tree

README.md

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# RawSocketPy
2+
3+
Raw socket is a layer 2 python library for communication using the MAC addresses only.
4+
5+
This allows you to create a custom made Ethernet/WiFi communication system which is **not** using IP nor TCP/UDP or to debug custom frames such as SERCOS III, Profibus, ARP, PTP, ...
6+
7+
**Pros:**
8+
9+
- Low level
10+
- Not using TCP-UDP/IP
11+
- Dead simple
12+
- Can broadcast
13+
- MTU of 1500
14+
15+
**Cons:**
16+
17+
- Low level
18+
- Not using TCP-UDP/IP
19+
- No encryption
20+
- No fragmentation
21+
- **Requires root**
22+
- MTU of 1500
23+
24+
## Installation
25+
26+
```bash
27+
# Soon
28+
sudo -H pip install rawsocketpy
29+
30+
# for now:
31+
git clone https://github.com/AlexisTM/rawsocket_python
32+
cd rawsocket_python
33+
sudo python setup.py install
34+
```
35+
36+
## Usage
37+
38+
### Sending
39+
40+
```python
41+
from rawsocketpy import RawSocket
42+
43+
# 0xEEFA is the ethertype
44+
# The most common are available here: https://en.wikipedia.org/wiki/EtherType
45+
# The full official list is available here: https://regauth.standards.ieee.org/standards-ra-web/pub/view.html#registries
46+
# Direct link: https://standards.ieee.org/develop/regauth/ethertype/eth.csv
47+
# You can use whatever you want but using a already use type can have unexpected behaviour.
48+
sock = RawSocket("wlp2s0", 0xEEFA)
49+
sock.send("some data") # Broadcast "some data" with an ethertype of 0xEEFA
50+
sock.send("personal data", dest="\xAA\xBB\xCC\xDD\xEE\xFF") # Send "personal data to \xAA\xBB\xCC\xDD\xEE\xFF with an ether type of 0xEEFA
51+
sock.send("other data", ethertype="\xEE\xFF") # Broadcast "other data" with an ether type of 0xEEFF
52+
53+
# On capable hardware, you can spoof your MAC address:
54+
sock.mac = "\x12\x13\x14\x15\x16\x17"
55+
sock.send("some data")
56+
```
57+
58+
### Receiving
59+
60+
On another machine, you can run the following:
61+
62+
```python
63+
from rawsocketpy import RawSocket, u_to_str
64+
65+
sock = RawSocket("wlp2s0", 0xEEFA)
66+
packet = sock.recv()
67+
68+
print(packet) # Pretty print
69+
packet.dest # unicode string "\xFF\xFF\xFF\xFF\xFF\xFF"
70+
packet.src # unicode string "\x12\x12\x12\x12\x12\x13"
71+
packet.type # unicode string "\xEE\xFA"
72+
packegt.data # unicode string "some data"
73+
74+
print u_to_str(packet.dest) # Human readable MAC: FF:FF:FF:FF:FF:FF
75+
print u_to_str(packet.type, "") # Human readable type: EEFA
76+
```
77+
78+
79+
## I want to contribue!!
80+
81+
You are free to contribue, the following capabilities are welcome:
82+
83+
- Windows compatibility
84+
- Python 3.x compatibility
85+
- Server implementation (callbacks on new data)
86+
87+
## Credits
88+
89+
- Alexis PAQUES - [@AlexisTM](https://github.com/AlexisTM/)

rawsocketpy/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Package init
2+
3+
from get_hw import get_hw, u_to_str
4+
from main import RawPacket, RawSocket

rawsocketpy/get_hw.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
4+
import socket
5+
import fcntl
6+
import struct
7+
import sys
8+
9+
if sys.version_info >= (3,0):
10+
import binascii
11+
def get_hw(ifname):
12+
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
13+
info = fcntl.ioctl(s.fileno(), 0x8927, struct.pack('256s', bytes(ifname[:15], 'utf-8')))
14+
return info[18:24]
15+
16+
def u_to_str(data, separator=":"):
17+
return separator.join("{:02x}".format(ord(c)) for c in data).upper()
18+
else:
19+
20+
def get_hw(ifname):
21+
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
22+
info = fcntl.ioctl(s.fileno(), 0x8927, struct.pack('256s', ifname[:15]))
23+
return info[18:24]
24+
25+
def u_to_str(data, separator=":"):
26+
return separator.join("{:02x}".format(ord(c)) for c in data).upper()
27+
28+
def main():
29+
print u_to_str(get_hw("wlp2s0"))
30+
31+
if __name__ == '__main__':
32+
main()

rawsocketpy/main.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import socket, select, struct, time
2+
from get_hw import get_hw, u_to_str
3+
4+
class RawPacket():
5+
def __init__(self, data):
6+
self.dest = ""
7+
self.src = ""
8+
self.type = ""
9+
self.data = ""
10+
self.success = False
11+
try:
12+
self.dest, self.src, self.type = data[0:6], data[6:12], data[12:14]
13+
self.data = data[14:]
14+
self.success = True
15+
except:
16+
self.success = False
17+
18+
def __repr__(self):
19+
return "".join([u_to_str(self.src), " == 0x", u_to_str(self.type, separator=""), " => ", u_to_str(self.dest), " - ", "OK" if self.success else "FAILED"])
20+
21+
def __str__(self):
22+
return "".join([self.__repr__(), ":\n", self.data])
23+
24+
class RawSocket(object):
25+
BROADCAST = "\xff\xff\xff\xff\xff\xff"
26+
def __init__(self, interface, protocol, sock=None, no_recv_protocol=False):
27+
if not 0x0000 < protocol < 0xFFFF:
28+
raise ValueError("Protocol has to be in the range 0 to 65535")
29+
self.protocol = socket.htons(protocol)
30+
self.ethertype = self.protocol_to_ethertype(protocol)
31+
self.interface = interface
32+
self.mac = get_hw(self.interface)
33+
if no_recv_protocol:
34+
self.sock = self.sock_create(self.interface, 0, sock)
35+
else:
36+
self.sock = self.sock_create(self.interface, self.protocol, sock)
37+
38+
@staticmethod
39+
def sock_create(interface, protocol, sock=None):
40+
if sock is None:
41+
sock = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, protocol)
42+
sock.bind((interface, 0))
43+
return sock
44+
45+
@staticmethod
46+
def protocol_to_ethertype(protocol):
47+
return chr((protocol & 0xFF00) >> 8) + chr(protocol & 0x00FF)
48+
49+
def send(self, msg, dest=None, ethertype=None):
50+
if ethertype is None: ethertype = self.ethertype
51+
if dest is None: dest = self.BROADCAST
52+
self.sock.send(dest + self.mac + ethertype + msg)
53+
54+
def recv(self):
55+
data = self.sock.recv(1500)
56+
return RawPacket(data)
57+
58+
def __str__(self):
59+
return self.interface
60+
61+
def main():
62+
na = NetworkAdapter("wlp2s0", 0xAA42)
63+
i = 0
64+
while True:
65+
try:
66+
na.send(str(i))
67+
time.sleep(0.1)
68+
i += 1
69+
except:
70+
break
71+
72+
if __name__ == '__main__':
73+
main()

setup.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from setuptools import setup
2+
3+
setup(name='rawsocketpy',
4+
version='0.1',
5+
description='This library allows you to implemnet a custom layer 2 communication using raw sockets in Python',
6+
url='https://github.com/AlexisTM/rawsocket_python',
7+
author='AlexisTM',
8+
author_email='alexis.paques@gmail.com',
9+
license='MIT',
10+
packages=['rawsocketpy'],
11+
zip_safe=False)

0 commit comments

Comments
 (0)