RAW клиент-серверный сокет Python

Я хотел бы реализовать сокет RAW на Python, а затем отправлять данные с клиента на сервер.

В отличие от обычного сокета я попытался использовать следующее определение

s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW)

но команды как

s.listen(1), s.connect()

не работают. Я понятия не имею, как программировать Client.py и Server.py. Кто-нибудь может мне помочь?


person rebrid    schedule 11.11.2015    source источник
comment
Возможный дубликат Как использовать Raw Socket в Python?   -  person Torxed    schedule 11.11.2015


Ответы (2)


Это потому, что необработанный сокет вообще не использует библиотеку 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
comment
Спасибо за хороший ответ. На самом деле мне придется создать свой собственный пакет (dst-адрес заголовка и т.д.), и я собираюсь сделать это с помощью Scapy. Но теперь моя проблема в том, что я даже не знаю, какой код у клиента и сервера для создания сокета без обмена данными. - person rebrid; 11.11.2015
comment
Хорошо, может быть, я смогу создать сокет сейчас, но получаю эту ошибку: starting up on 192.168.240.1 port 10000 waiting for a connection Traceback (most recent call last): File "rawserve.py", line 20, in <module> connection, client_address = sock.accept() File "/usr/lib/python2.7/socket.py", line 202, in accept sock, addr = self._sock.accept() socket.error: [Errno 122] Operation not supported Сервер ожидает подключения клиента. Как я могу это сделать? - person rebrid; 11.11.2015
comment
@ m.ridolfi Не обращайте внимания на .accept() и все, что вы знаете .. Просмотрите мое редактирование моего сообщения .. Снова прочтите это stackoverflow.com/questions/1117958/, который дает вам ЯСНЫЙ пример того, как настроить серверный сокет, я включить его также в мою редакцию. - person Torxed; 12.11.2015
comment
Спасибо, моя проблема в том, что я не могу отправить пакет. Вы имеете в виду, что я должен написать код для отправки SYN-сообщения или это будет сделано автоматически? Можете ли вы проверить мою текущую ситуацию: ссылка ? - person rebrid; 12.11.2015
comment
@ m.ridolfi Нашел мой старый код, как и обещал: github.com/Torxed/Scripts / tree / master / python / Лаборатория - person Torxed; 16.11.2015

Необработанные сокеты не поддерживают соединение, а это означает, что прослушивание и принятие не будут работать. Тем не менее, вы можете использовать эту библиотеку Python: rawsocketpy она позволяет использовать сырые сокеты на уровне 2 и реализует сервер понравился вариант.

#!/usr/bin/env python
from rawsocketpy import RawSocket

sock = RawSocket("wlp2s0", 0xEEFA)
sock.send("some data")
sock.send("personal data", dest="\xAA\xBB\xCC\xDD\xEE\xFF")

или форма сервера:

#!/usr/bin/env python
from rawsocketpy import RawRequestHandler, RawAsyncServerCallback
import time

def callback(handler, server):
    print("Testing")
    handler.setup()
    handler.handle()
    handler.finish()

class LongTaskTest(RawRequestHandler):
    def handle(self):
        time.sleep(1)
        print(self.packet)

    def finish(self):
        print("End")

    def setup(self):
        print("Begin") 

def main():
    rs = RawAsyncServerCallback("wlp2s0", 0xEEFA, LongTaskTest, callback)
    rs.spin()

if __name__ == '__main__':
    main()
person Alexis Paques    schedule 09.08.2018
comment
Последнее сообщение коммита - это отказ от совместимости с Python3 и ожидание новой функции to_bytes, которая не внушает доверия. - person Matthew Lundberg; 11.08.2020