Я использую scapy для отправки данных по ICMP. Мне нужно отправить изображение и другие файлы через ICMP с помощью scapy. Я могу отправлять простые строки в ICMP. Как я мог отправить изображение и другие файлы?
Как отправить изображение в поле данных ICMP с помощью ICMP
Ответы (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 и заметил, что принимающее ядро не передавало пакет моему обработчику. Поэтому я изменил свое объяснение, чтобы учесть это.
Думаю, вы узнали, почему изобретатели Интернета разработали протокол TCP. В пакете ICMP есть ограничение на размер полезной нагрузки. В большинстве сетей общий лимит на размер пакетов Ethernet составляет 1500 байт, поэтому с 20-байтовым IP-заголовком и 8-байтовым заголовком ICMP максимальный размер полезной нагрузки в одном пакете будет 1472 октета. Для многих файлов изображений этого недостаточно.
Вам нужен способ разбить поток данных изображения на части примерно такого размера, отправить их в нескольких пакетах ICMP и повторно собрать их в поток данных на приемнике.
Учитывая, что нет гарантии, что пакеты ICMP будут получены в порядке, и действительно нет гарантии, что все они будут получены в порядке, вам нужно будет ввести какой-то порядковый номер в отдельные пакеты, чтобы вы могли повторно собрать их по порядку. Вам также может потребоваться некоторая логика тайм-аута, чтобы ваша принимающая машина могла определить, что пакет был потерян, и поэтому изображение никогда не будет завершено.
RTP и TCP - это два протокола, наложенных на IP, которые делают это. Они подробно документированы, и вы можете узнать из этих документов, как делать то, что вы пытаетесь сделать, а также узнать о некоторых подводных камнях и последствиях для производительности.