Сырые сокеты и sendto в питоне

Я работаю над интеграцией Scapy с Twisted, но натолкнулся на эту очень странную ошибку в OSX, которую, похоже, не могу понять.

По сути, я не могу отправить действительный пакет TCP (включая заголовки IP) через необработанный сокет. Это то, что я делаю:

import socket
from scapy.all import IP, TCP
pkt = IP(src='0.0.0.0', dst='127.0.0.1')/TCP()
spkt1 = str(pkt)
outs = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
outs.setsockopt(socket.SOL_IP, socket.IP_HDRINCL, 1)
outs.sendto(spkt1, ('127.0.0.1', 0))

Когда я запускаю это, я получаю следующую ошибку:

outs.sendto(spkt1, ('127.0.0.1', 0)) socket.error: [Errno 22] Invalid argument

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

import base64
spkt1 = base64.b64decode("RQAAKAABAABABvvOAAAAAH8AAAEAFABQAAAAAAAAAABQAiAAEH4AAA==")

Очень странно, что пакет, который почти идентичен, похоже, отправляется правильно:

spkt2 = base64.b64decode("RQBAAAWwAAACBgAAAAAAAH8AAAEAyAOEAAAAAAAAAACwAgDIAHsAAAIEBbQBAwMBAQEICk3PUjMAAAAABAIAAA==")

Вот как выглядят два пакета:

SPKT1
0000   45 00 00 28 00 01 00 00  40 06 FB CE 00 00 00 00   E..([email protected]
0010   7F 00 00 01 00 14 00 50  00 00 00 00 00 00 00 00   .......P........
0020   50 02 20 00 10 7E 00 00                            P. ..~..
SPKT2
0000   45 00 40 00 05 B0 00 00  02 06 00 00 00 00 00 00   [email protected]
0010   7F 00 00 01 00 C8 03 84  00 00 00 00 00 00 00 00   ................
0020   B0 02 00 C8 00 7B 00 00  02 04 05 B4 01 03 03 01   .....{..........
0030   01 01 08 0A 4D CF 52 33  00 00 00 00 04 02 00 00   ....M.R3........

Проверяя их в wireshark, они отличаются только в части TCP.

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

У кого-нибудь есть идея, почему это может происходить?

РЕДАКТИРОВАТЬ:

Этот пакет действительно работает:

pkt = IP(len=16384, src='0.0.0.0', dst='127.0.0.1',
     id=RandShort(), ttl=2)/TCP(sport=255,
      dport=900, flags="S", window=200,
      options=[('MSS', 1460), ('WScale', 2)])
spkt = bytes(pkt)
spkt += '\x00'*20

Если вы не добавляете нули, это не работает.

 Yuval Adam12 июн. 2012 г., 23:38
FWIW, я получаю ту же ошибку в вашем коде.
 David Wolever12 июн. 2012 г., 22:27
Не могли бы вы исправитьimport в вашем первом фрагменте кода? (также, забавный факт, пока я читаю запрос вашего вопроса: вы можете использовать"…".decode("base64") а также"…".encode("base64") вместоimport base64). Хорошо, извините, не могу помочь с этим. Но у тебя есть мой голос.
 Arturo Filastò - hellais12 июн. 2012 г., 22:33
да, исправил импорт.

Ответы на вопрос(6)

Python 2.7.1+ (r271:86832, Apr 11 2011, 18:13:53) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import socket
>>> from scapy.all import IP, TCP
WARNING: No route found for IPv6 destination :: (no default route?)
>>> pkt = IP(src='0.0.0.0', dst='127.0.0.1')/TCP()
>>> spkt1 = str(pkt)
>>> 
>>> outs = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
>>> outs.setsockopt(socket.SOL_IP, socket.IP_HDRINCL, 1)
>>> outs.sendto(spkt1, ('127.0.0.1', 0))
40

у меня нет ошибок при записи этого конкретного набора пакетов - я использую x86_64 с ядром 2.6.38- * Gnu / Linux.

Возможно, ваша проблема связана с повреждением мозга в Mac OS X с помощью необработанных сокетов?

Решение Вопроса

что сырые сокеты просто прослушиваются, чтобы их можно было использовать. Тем более что это программное обеспечение должно быть кроссплатформенным, причуды для OSX могут быть неприменимы к другим ОС.

В настоящее время я просто обернул "сокеты" которые предоставлены Scapy. В будущем я напишу что-то, что зависит только от libdnet (как это делает scapy для написания сырых фреймов).

Вы можете найти это реализованным здесь:

https://github.com/hellais/txscapy

но я думаю, что это может быть связано с минимальным размером полезной нагрузки Ethernet.

Отвикипедия:

The minimum payload is 42 octets when 802.1Q tag is present and 46 octets when absent.

Ваш первый примерный пакет был только 40 байтов, поэтому он был бы ниже предела в любом случае. Вы можете поэкспериментировать с изменением заполнения от 20 байтов до этих значений, чтобы убедиться, что оно перестает работать при одном из ограничений.

Если так, то поведение имеет смысл; ОС отклоняет пакет, потому что вы не даете ему достаточно данных для создания действительного пакета.

impacket модуль имеетping.py скрипт для пинга хостов. В Mac OS X Lion я получил ошибку при использовании этого скрипта:

Traceback (most recent call last):
  File "/private/var/www/env/bin/ping.py", line 73, in <module>
    s.sendto(ip.get_packet(), (dst, 0))
socket.error: [Errno 22] Invalid argument

Но в Ubuntu все работает нормально, и я получаю ответы от хостов.

чтобы быть действительным. И есть также область отступа на конце.

Таким образом, в зависимости от параметров IP, установленных в заголовке, & # x2014; & # x2009; который занимает переменное количество битов; & # x2014; & # x2014;and обивка.

Похоже, разные ОС справляются с этим по-разному. Можно подумать, что умная ОС сделает это за вас.

... не выглядит для меня как действительный IP-адрес источника. Меняет ли это значение на любое другое значение?

 12 июн. 2012 г., 23:44
Похоже, это не имеет значения.
 Arturo Filastò - hellais13 июн. 2012 г., 12:23
Да, это, вероятно, ошибка OSX. Я просто собираюсь отказаться от использования сырых сокетов, так как они ужасны для кроссплатформенной поддержки и просто использовать libdnet.
 13 июн. 2012 г., 00:05
Weird. Не знаю. Моя следующая мысль - ядро OS X полно неясных ошибок, подобных этой. ;)
 Arturo Filastò - hellais12 июн. 2012 г., 23:48
нет, это не имеет никакого значения. Как ни странно, этот пакет, например, действительно работает: pkt = IP (len = 16384, src = "0.0.0.0", dst = "127.0.0.1", id = RandShort (), ttl = 2 ) / TCP (sport = 255, dport = 900, flags = "S", window = 200, options = [("MSS", 1460), ("WScale", 2)]) spkt = bytes (pkt ) spkt + = '\ x00' * 20 Если вы не добавите 20 нулей, произойдет сбой, как и в случае с другими нулями. (добавление пакета в сообщение, правильно отформатированный)

Ваш ответ на вопрос