Как отправить изображение в поле данных ICMP с помощью ICMP

Я использую scapy для отправки данных по ICMP. Мне нужно отправить изображение и другие файлы через ICMP с помощью scapy. Я могу отправлять простые строки в ICMP. Как я мог отправить изображение и другие файлы?


person user567879    schedule 16.03.2014    source источник


Ответы (2)


Я не знаю scapy, поэтому моим ответом будет алгоритм и прямой питон.

Чтобы отправить файлы изображений, вам нужно разбить изображение на части, помня, что вам понадобится какой-то механизм для отслеживания порядка того, какой кусок был отправлен.

Для начала прочтите файл изображения как двоичный файл. Затем решите, на какое количество двоичных данных следует разделить. Учитывая MTU 1500, я бы предложил 1500 - заголовок IP - заголовок ICMP или 1472, чтобы избежать фрагментации IP. Кроме того, я бы предложил использовать 16-битное или 32-битное число, чтобы отслеживать порядок отправленных фрагментов, а также вычесть это из 1500. Пример: 1500 - IP - ICMP - 4 = 1468.

Используя приведенный выше пример, я бы разбил изображение следующим образом:

image = file("/path/to/file","rb").read()
chunk = []
interval = 1500 - 20 - 8 - 4
for n in range(0, len(image), interval):
    chunk.append(image[n:n + interval])

Теперь, когда изображение разбито на куски, я бы добавил байты отслеживания к каждому фрагменту. Он может быть с префиксом или суффиксом, по вашему выбору. Я выбрал префикс:

for n in range(len(chunk)):
    chunk[n] = struct.pack(">I", n) + chunk[n]

Теперь, когда у нас есть фрагменты, отмеченные для отслеживания, нам нужно создать заголовок ICMP с добавлением каждого фрагмента. Но какой тип / код мы используем? В этом случае мы создадим пакет ECHO REQUEST (другие типы, такие как 0 или 3, являются незапрашиваемыми и могут привести к тому, что принимающее ядро ​​не будет пересылать пакет вашим обработчикам сокетов ICMP). Также важно отметить: вам понадобится код контрольной суммы для вычисления контрольной суммы ICMP:

icmp_chunks = []
for img_piece in chunk:
    icmp = struct.pack(">BBHHH%ds" % len(img_piece), 8, 0, 0, 0, 0, img_piece)
    icmp = struct.pack(">BBHHH%ds" % len(img_piece), 8, 0, cksum(icmp), 0, 0, img_piece)
    icmp_chunks.append(icmp)

Чтобы повторить, обратите внимание на параметр cksum (icmp) во втором пакете заголовка icmp. Эта контрольная сумма необходима, иначе принимающее ядро ​​может не пересылать пакет ни одному из обработчиков сокетов ICMP, если он неверен. Также обратите внимание, что 4-й и 5-й параметры равны нулю: это поля «идентификатор» и «порядковый номер». Обычно они используются для хранения идентификатора процесса и инкрементного номера (соответственно). Объекты Socket делают это, чтобы отслеживать, какой сокет что и сколько отправил. В этом случае использования, поскольку мы отправляем незапрашиваемый ECHO REPLY, вы можете закодировать принимающую сторону для поиска типа 0 и дальнейшего поиска байтов отслеживания в отправленном фрагменте. Таким образом, пока я оставляю поля идентификатора и последовательности равными нулю. Если вам интересно, почему я создал два заголовка icmp, то это потому, что ядро ​​основывает правильно вычисленную контрольную сумму на нулевом поле начальной контрольной суммы.

На данный момент у нас есть заголовки icmp и мы готовы отправить:

for i in icmp_chunks:
    [socket].sendto(i, ("hostname-or-ip", 0))

Я предполагаю, что объект [socket] либо scapy, либо ваш собственный объект сокета.

На принимающей стороне вы считываете данные и ищите полезную нагрузку изображения, восстанавливая каждую полезную нагрузку обратно в исходный порядок. Однако вам все равно понадобится способ выяснить, действительно ли все полученные фрагменты являются ими. Возможно, подумайте о том, как структурировать начальную последовательность байтов, указывающую общий ожидаемый размер, перед отправкой фрагментов изображения.

Надеюсь это поможет.

ОБНОВЛЕНИЕ: я тестировал отправку незапрашиваемых пакетов типа 0 в Ubuntu Linux и заметил, что принимающее ядро ​​не передавало пакет моему обработчику. Поэтому я изменил свое объяснение, чтобы учесть это.

person Eugene C.    schedule 18.03.2014

Думаю, вы узнали, почему изобретатели Интернета разработали протокол TCP. В пакете ICMP есть ограничение на размер полезной нагрузки. В большинстве сетей общий лимит на размер пакетов Ethernet составляет 1500 байт, поэтому с 20-байтовым IP-заголовком и 8-байтовым заголовком ICMP максимальный размер полезной нагрузки в одном пакете будет 1472 октета. Для многих файлов изображений этого недостаточно.

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

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

RTP и TCP - это два протокола, наложенных на IP, которые делают это. Они подробно документированы, и вы можете узнать из этих документов, как делать то, что вы пытаетесь сделать, а также узнать о некоторых подводных камнях и последствиях для производительности.

person O. Jones    schedule 16.03.2014