![]() |
Продолжим круиз по стеку протоколов TCP/IP, и на этот раз остановимся на ICMP.
В реализации этого протокола нет ничего сложного – он примитивен как амёба. Однако в умелых руках ICMP превращается в грозное оружие, из-за чего Microsoft поспешила на корню отрубить к нему доступ, оставив прогерам на растерзание лишь пару функций из библиотеки iphlpapi.dll – вот их список:
5.3.0. Назначение протокола ICMP Под аббревиатурой ICMP кроется "Internet Control Message Protocol". Протокол был введён для обмена сообщениями об ошибках между маршрутизаторами. Например отправили мы из своей сети пакет адресату, а адресат находится в другой сети и в данный момент по каким-то причинам не доступен (узел выключен, или кабель перебит). В этом случае, можно долго томиться в ожидании ответа, и по истечении тайм-аута так и не узнать об истинной причине отказа. Здесь и приходит на помощь ICMP, который оправляет нам смс'ку с кодом ошибки. Примечательным является тот факт, что ICMP является частью протокола IP и делит с ним ложе на сетевом уровне(2) стека TCP/IP. Такой расклад приводит к тому, что хоть маршрутизатор и отправит нам сообщение об ошибке, нет никакой гарантии что мы его получим. Из протоколов сетевого стека, гарантировать доставку может только протокол транспортного уровня TCP, а он находится по лестнице выше IP. Задачей протокола ICMP является передача информации о проблемах в коммуникационной среде, но отнюдь не повышение уровня надёжности IP. https://forum.antichat.xyz/attachmen...40f5a55bb1.png В глобальных сетях маршрутизатор (он-же шлюз и роутер)представляет собой специально выделенный для перенаправления трафика компьютер. Он имеет карту IP-адресов своих клиентов, в числе которых и следующие в цепочки шлюзы. Всё-что делает маршрутизатор, это сверяет поле с адресом получателя в IP-заголовке пакета со своей таблицей маршрутизации, и если такого IP-адреса не обнаруживает, то перенаправляет трафик соседнему маршрутизатору. На рисунке представлена схема подключения нескольких локальных сетей, при помощи маршрутизаторов R1-RN (route): https://forum.antichat.xyz/attachmen...57d4550e34.png Здесь видно, что если узел из сети(B) захочет переслать пакет например узлу в сети(С), то пакет ждёт экстремальное путешествие – это коммутатор и сервак в своём периметре... после чего пакет выходит наружу и прямиком попадёт в лапы маршрутизатора R2. В маршрутной карте R2 прописаны IP-адреса только узлов сети(В) и оккупировавших его с двух сторон соседних маршрутизаторов R1 и R3. Теперь R2 уменьшает в IP-заголовке пакета значение TTL на единицу, и перенаправляет пакет по цепочке дальше, в объятия маршрутизатора R3. Тот видит, что указанный IP-адрес имеется в его таблице, и пропускает пакет в свою сеть. В контексте данной темы, декремент значения TTL для нас в приоритете – именно на этот факт опирается утилита TRACERT, которая работает как-раз по протоколу ICMP. Нужно иметь в виду, что маршрутизаторы общаются между собой по своим правилам. Если сеть небольшая, таблица маршрутизации может заполняться админом вручную. Однако в больших сетях таблицы заполняются уже динамически, самим маршрутизатором при помощи ARP-запросов. Например он может на автомате определять добавление новой сети, недоступность пункта назначения по тайм-ауту, добавление в сеть нового маршрутизатора, который может обеспечить более короткий путь к месту назначения и т.д. Протоколом маршрутизации внутри автономных систем являлся протокол внутреннего шлюза "Interior Gateway Protocol" или IGP. Его расширением стал "Routing Information Protocol" RIP (не путать с посмертной надписью). Однако новый протокол "Open Shortest Path First" OSPF имеет более продвинутый набор возможностей, и в дословном переводе означает "Сначала открывать самый короткий путь" – в этом случае маршрутизатор отправляет ICMP сообщение типа(5) - Redirect. На радость устаревшим IGP и RIP, большинство маршрутизаторов поддерживают все перечисленные протоколы, хотя пальмовую ветвь носит OSPF. 5.3.1. Обзор протокола ICMP и типы его ошибок Сообщения ICMP обычно содержат информацию об ошибках при обработке пакетов маршрутизаторами. Вполне возможна ситуация, когда сообщения будут передаваться в непрерывном режиме, полностью забивая пропускную способность канала. Чтобы предотвратить такой беспредел, маршрутизаторы не должны передавать сообщения ICMP, которые связаны с ошибками самих-же сообщений ICMP. При возникновении ошибок в процессе обработки нескольких кадров одного (фрагментированного) пакета, сообщения должны передаваться только для первого фрагмента. В прошлой части говорилось, что первым считается тот, у которого значение "Offset" в заголовке равно нулю. В качестве несущего, ICMP использует ненадёжный и без установки связи протокол IP. Существуют две категории сообщений – сообщения об ошибках, и управляющие запросы. Первые сообщают о проблемах, с которыми может столкнуться маршрутизатор при обработке пакета. В свою очередь управляющие сообщения всегда ходят парами "запрос-ответ", и помогают админу выудить конкретную информацию у маршрутизатора – это касается таких инструментов как PING и TRACEROUTE. Сообщения ICMP инкапсулируются в пакеты IP и имеют свой формат. Именно по этой причине мастдай наглухо забил гвоздями дверь на этот уровнь, т.к. при благоприятных условиях мы сами должны были формировать заголовки IP и ICMP, а значит без труда могли подменить IP-адрес отправителя. Такой/левый пакет по конвейеру поступил-бы на физический уровень стека TCP/IP, где драйвер TDI дополнил-бы пакет только MAC-адресом и выпустил-бы его в белый свет. В следующей части мы вернёмся к этому вопросу и рассмотрим его подробней. Детали протокола ICMP описывает спецификация RFC-792. Если коротко, то нужно создать структуру ICMP_Header и разместив её после IP-заголовка, отправить получателю посредством WinSock функции sendto(). В таблицах ниже представлена структура ICMP-сообщения и возможные варианты поля Type: https://forum.antichat.xyz/attachmen...4cb8ddc4b1.png Обычно прикладные программы только получают сообщения об ошибках – отправкой занимаются системные демоны. В числе запросов которые мы могли-бы отправить можно выделить лишь сообщение с типом(8) – это знакомый большинству из нас эхо-запрос PING. Но и в этом случае, как упоминалось выше, мастдай (редиска) забрал у нас эти права, а взамен вручил уже готовую функцию IcmpSendEcho(). Так-что нам остаётся лишь фильтровать входящий трафик на сообщения с ошибками. Выход – или ставить W2K (тогда о переносимости приложения можно забыть), или менять коня на Linux (что для привыкших к Win смерти подобно). 5.3.2. Практика – пишем утилиту PING Здесь может возникнуть логичный вопрос – зачем тратить время и силы на свой пинг, когда в системе есть уже готовая утилита? Есть-то она есть, только каждый раз звать её из своего приложения слишком накладно. Можно даже вставить в код профайлер, и засечь время выполнения внешней утилиты – результат явно не обрадует. Если мы захотим из своего кода пропинговать не один, а например сразу сотни узлов (создав для каждого свой поток), то проще добежать до них пешком, чем воспользоваться системной тулзой PING. Поэтому практичней вызывать оптом и врозницу всего одну функцию IcmpSendEcho() с таким прототипом.. В случае ошибки, в регистре EAX она возвращает (-1), иначе – кол-во ответов хоста (как правило один): C-подобный: Код:
IcmpSendEchoC-подобный: Код:
struct IP_OPTIONS_INFOC-подобный: Код:
struct ICMP_ECHO_REPLYC-подобный: Код:
format pe consoleСкрин снифера " Wireshark" показывает, что ICMP-пакеты не выходят из уровня IP. Хоть я и отправлял запросы из своего пользовательского приложения, транспортные уровни TCP и UDP стека протоколов остались не при делах, и даже не подозревают об отправки мной запроса. Другими словами, в протоколе ICMP вообще отсутствует понятие порт, и весь обмен происходит исключительно на уровне маршрутизаторов IP. 5.3.3. Утилита TRACEROUTE ..это из той-же кухни, что и PING. Основное назначение – хитростью отследить маршрут пакета от источника, к месту назначения. Мы уже знаем, что каждый маршрутизатор в сети уменьшает на единицу значение TTL в IP-заголовке пакета. Если маршрутизатор обнаруживает пакет с TTL=0, он дропает его и отправляет нам ICMP-сообщение типа(11), что означает "Лимит времени истёк"(см.таблицу с кодами ошибок выше). Так-как сообщение отправляет именно маршрутизатор, значит он-же и вставит в сообщение свой IP-адрес. Айпишник в полученной мессаге сдаёт маршрутизатор с потрахами и нам остаётся лишь вывести его на экран. TRACEROUT – чемпион по бегу в мешках. Он прыгает от маршрутизатора к маршрутизатору собирая их айпи. Важным моментом в этой махинации является то, что установив сначала TTL=1, при каждом последующем запросе мы должны увеличивать его на единицу, чтобы очередной маршрутизатор передавал наш запрос на один шаг дальше. Когда запрос минуя все маршрутизаторы дойдёт до адресата, ошибка в поле "Status" структуры ICMP_ECHO_REPLY будет равна нулю, ..т.е. всё ок! В противном случае, там будет красоваться код 0x2B05 (11013) = IP_TTL_EXPIRED_TRANSIT. Возможные варианты этого поля перечислены ниже: Воспользовавшись этим нехитрым приёмом, мы можем написать свой TRACERT. Вообще, функционал любого кода зависит от конкретной задачи, поэтому я не стал тут выворачиваться наизнанку, и ограничился лишь выводом IP-адресов и времени прохождения пакета в обе стороны. Вот пример исходника, который вы можете заточить под себя.. C-подобный: Код:
format pe consoleНа всякий/пожарный, в скрепке цепляю обновлённый вариант инклуд, в который добавил некоторые структуры и константы ошибок. |
Ура ! Новая статья ! Суицид откладывается.
|
ТС случаем на Си не пишет? Может такое же, только на Си?
|
Цитата:
Но речь шла конкретно о внедрении в память к другому приложению. По поводу этой программы, мне кажется ничего особенного здесь нет. Создаёте проект, выбираете консольное приложение, инклюдите библиотеки, в третьей главе о практике были примеры циклов и ветвлений. Советую то что стоит после cinvoke/invoke гуглить (это обычно названия функций), в MSDN даётся полная информация о функциях. |
Цитата:
а на сишке есть уже готовые примеры, хоть на том-же MSDN по запросу этой функции. Чтобы сделать из него tracert, просто увеличивайте ttl на единицу, и всё. |
Цитата:
|
| Время: 00:57 |