Как я могу использовать Raw Socket в Python? - PullRequest
32 голосов
/ 13 июля 2009

Я пишу приложение для проверки сетевого драйвера для обработки поврежденных данных. И я думал об отправке этих данных с использованием необработанного сокета, чтобы они не были исправлены стеком TCP-IP отправляющего компьютера.

Я пишу это приложение исключительно для Linux. У меня есть примеры кода использования необработанных сокетов в системных вызовах, но я действительно хотел бы, чтобы мой тест был как можно более динамичным, и написал большинство, если не все, на Python.

Я немного погуглил в Интернете объяснения и примеры использования сырых сокетов в python, но не нашел ничего по-настоящему поучительного. Просто очень старый пример кода, который демонстрирует идею, но ни в коем случае не работает.

Из того, что я понял, использование Raw Socket в Python по семантике практически идентично использованию UNIX-сокета raw, но без struct s, определяющих структуру пакетов.

Мне было интересно, будет ли лучше даже написать не тестовую часть сокета теста на Python, а на C с системными вызовами, и вызвать его из основного кода Python?

Ответы [ 8 ]

42 голосов
/ 16 июня 2011

Вы делаете это так:

Сначала вы отключите автоматическую контрольную сумму вашей сетевой карты:

sudo ethtool -K eth1 tx off

А затем отправьте свой хитрый фрейм из Python 2 (вам придется самостоятельно конвертировать в Python 3):

#!/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, 
# but you could have anything you want instead
# Have a look at the 'struct' module for more 
# flexible packing/unpacking of binary data
# and 'binascii' for 32 bit CRC
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)

Готово.

10 голосов
/ 13 июля 2009

Системные вызовы сокетов (или Winsocks в Windows) уже включены в стандартный модуль socket: intro , reference .

Я никогда не использовал необработанные сокеты, но похоже, что они могут использоваться с этим модулем:

Последний пример показывает, как написать очень простой сетевой сниффер с raw розетки на винде. Пример требует прав администратора для изменить интерфейс:

import socket

# the public network interface
HOST = socket.gethostbyname(socket.gethostname())

# create a raw socket and bind it to the public interface
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_IP)
s.bind((HOST, 0))

# Include IP headers
s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)

# receive all packages
s.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)

# receive a package
print s.recvfrom(65565)

# disabled promiscuous mode
s.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)
2 голосов
/ 27 июля 2009

В конце концов, лучшим решением для этого случая было написать все это на C, потому что это не большое приложение, поэтому было бы дороже написать такую ​​маленькую вещь на более чем 1 языке.

После долгих попыток поработать с сокетами C и Python RAW, я в итоге предпочел сокеты C RAW. Для записи заголовков пакетов RAW-сокеты требуют изменения уровня битов менее 8 битных групп. Иногда пишу только 4 бита или меньше. Python не помогает в этом, тогда как Linux C имеет полный API для этого.

Но я определенно считаю, что, если бы только эта небольшая часть инициализации заголовка была удобно обработана в python, я бы никогда не использовал здесь C.

2 голосов
/ 13 июля 2009

Является ли этот старым кодом, который вы упомянули, найдя? Это выглядит разумно для меня, но я сам не проверял (или много использовал сырые сокеты). Этот пример из документации показывает, как использовать необработанные сокеты для перехвата пакетов, и это выглядит достаточно похоже.

1 голос
/ 28 сентября 2012
s = socket(AF_PACKET, SOCK_RAW)
s = socket(PF_PACKET, SOCK_RAW)

результат:

[root@localhost python]# tcpdump -i eth0

capture size 96 bytes
11:01:46.850438 

01:02:03:04:05:06 (oui Unknown) > 01:02:03:04:05:06 (oui Unknown), ethertype Unknown (0x0801), length 85:

        0x0000:  5b5b 5b5b 5b5b 5b5b 5b5b 5b5b 5b5b 5b5b  [[[[[[[[[[[[[[[[
        0x0010:  5b5b 5b5b 5b5b 5b5b 5b5b 5b5b 5b5b 5041  [[[[[[[[[[[[[[PA
        0x0020:  594c 4f41 445d 5d5d 5d5d 5d5d 5d5d 5d5d  YLOAD]]]]]]]]]]]
        0x0030:  5d5d 5d5d 5d5d 5d5d 5d5d 5d5d 5d5d 5d5d  ]]]]]]]]]]]]]]]]
        0x0040:  5d5d 5d00 0000 00                        ]]]....
0 голосов
/ 08 июня 2019

FTR, если вам нужен доступ 2-го уровня (Ethernet, RadioTap ...), который не будет изначально возможен в Windows (на сегодняшний день).

Если вы хотите получить доступ к тем с кроссплатформенным методом, вы можете выбрать libpcap и его привязки Python (так как он будет использовать Npcap/WinPcap для работы в Windows).

У вас есть множество привязок Python для libpcap на всех уровнях (очень высокий или очень низкий).

Мой совет - использовать сокеты scapy (, даже если вы не используете его для анализа ), которые реализуют как вызовы Native, так и Libpcap, (и пусть вы выбрали против них с conf.use_pcap = True)

from scapy.all import conf
# conf.use_pcap = True (will be automatic if required)
socket = conf.L2socket(iface="eth0")
# On any platforms, you have `get_if_list()` in `scapy.all` available, to see the ifaces available. You could also ignore it to use the default one
0 голосов
/ 09 августа 2018

Вы можете использовать эту библиотеку Python: rawsocketpy она позволяет использовать необработанные сокеты на уровне 2 => Нет заголовков IP / TCP / UDP.

#!/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()
0 голосов
/ 13 июля 2009

Класс сокета должен помочь. Если нет, то вам нужно либо написать модуль Python на C, либо просто использовать C. Смотрите http://mail.python.org/pipermail/python-list/2001-April/077454.html.

Базовый поиск в Google нашел это.

Я на самом деле пробовал пример кода, на который указал "раскрутка". AF_PACKET у меня работал в python 2.7.4

...