Это потому, что необработанный сокет вообще не использует библиотеку Ethernet / TCP / IP. Это сокет RAW, вы отвечаете за любые данные, которые отправляете. Вы также отвечаете за подключение к своему узлу, отправив правильный запрос SYN / ACK.
Традиционные сокеты - это уровень «абстракции», на котором вы можете отправлять полезную нагрузку (данные). Это означает, что вы подключаете свой сокет к месту назначения, вы сообщаете сокету, какие данные отправлять, предполагая, что вы используете сокет на основе TCP, к вашим данным будет добавлен заголовок, соответствующий протоколу и версии TCP, и ваши данные могут быть сегментированы в зависимости от того, сколько данных вы пытаетесь передать.
Все это происходит автоматически с традиционной розеткой.
Примерно так выглядит заголовок TCP (вырванный из контекста, но он даст вам представление):
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |U|A|P|R|S|F| |
| Offset| Reserved |R|C|S|S|Y|I| Window |
| | |G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Обратите внимание, что вы обычно делаете данные, но при работе с сокетами RAW вам необходимо отправить все эти информационные блоки по кабелю Ethernet.
Я мог бы опубликовать код позже сегодня вечером, возможно, если кто-то меня не опередит, но вот хороший короткий пример использования: Как использовать Raw Socket в Python?
tl;dr:
Вам нужно создать заголовок Ethernet и заголовок TCP и добавить в них свои данные в соответствии со стандартом RFC (это может быть хорошим местом для начала: https://tools.ietf.org/html/rfc793). Затем вам нужно «просто» отправить это на свой «сокет». В сокетах RAW нет никакой магии, вы создаете свой заголовок с адресом источника + назначения и отправляете свои полезные данные по кабелю, надеясь, что вы правильно построили пакет.
Ответ на комментарии:
socket.accept()
- Эта функция используется в традиционных сокетах для «хранения» информации о сеансе (Источник: Порт -> Назначение: Порт). Эта функция берет клиентов из буферизованной очереди попыток входящего соединения и «активирует» их. Это не относится к необработанным сокетам, причина в том, что уровень абстракции от обычных сокетов снова отсутствует. Ваш сокет RAW будет прослушивать любые входящие данные (не соединения), то есть вы отвечаете за получение сначала SYN
пакета, на который вам нужно ответить SYN-ACK
, в котором вы получите последний ACK
. На этом этапе вы можете отправлять данные между вами с правильной информацией (исходный порт и т. Д.).
Вот хорошая (ASCII) блок-схема уровня абстракции, представленного в обычном сокете:
+---------+ ---------\ active OPEN
| CLOSED | \ -----------
+---------+<---------\ \ create TCB
| ^ \ \ snd SYN
passive OPEN | | CLOSE \ \
------------ | | ---------- \ \
create TCB | | delete TCB \ \
V | \ \
+---------+ CLOSE | \
| LISTEN | ---------- | |
+---------+ delete TCB | |
rcv SYN | | SEND | |
----------- | | ------- | V
+---------+ snd SYN,ACK / \ snd SYN +---------+
| |<----------------- ------------------>| |
| SYN | rcv SYN | SYN |
| RCVD |<-----------------------------------------------| SENT |
| | snd ACK | |
| |------------------ -------------------| |
+---------+ rcv ACK of SYN \ / rcv SYN,ACK +---------+
| -------------- | | -----------
| x | | snd ACK
| V V
| CLOSE +---------+
| ------- | ESTAB |
| snd FIN +---------+
| CLOSE | | rcv FIN
V ------- | | -------
+---------+ snd FIN / \ snd ACK +---------+
| FIN |<----------------- ------------------>| CLOSE |
| WAIT-1 |------------------ | WAIT |
+---------+ rcv FIN \ +---------+
| rcv ACK of FIN ------- | CLOSE |
| -------------- snd ACK | ------- |
V x V snd FIN V
+---------+ +---------+ +---------+
|FINWAIT-2| | CLOSING | | LAST-ACK|
+---------+ +---------+ +---------+
| rcv ACK of FIN | rcv ACK of FIN |
| rcv FIN -------------- | Timeout=2MSL -------------- |
| ------- x V ------------ x V
\ snd ACK +---------+delete TCB +---------+
------------------------>|TIME WAIT|------------------>| CLOSED |
+---------+ +---------+
Вот пример сервера:
#!/usr/bin/env python
from socket import socket, AF_PACKET, SOCK_RAW
s = socket(AF_PACKET, SOCK_RAW)
#s.bind(("eth1", 0))
# We're putting together an ethernet frame here,
# NOTE: Not a full TCP frame, this is important to remember!
src_addr = "\x01\x02\x03\x04\x05\x06"
dst_addr = "\x01\x02\x03\x04\x05\x06"
payload = ("["*30)+"PAYLOAD"+("]"*30)
checksum = "\x1a\x2b\x3c\x4d"
ethertype = "\x08\x01"
s.send(dst_addr+src_addr+ethertype+payload+checksum)
Нашел старый код, над которым я только начал работать, может пригодиться: https://github.com/Torxed/Scripts/tree/master/python/Laboratory
person
Torxed
schedule
11.11.2015