Бедному Диалапщику посвящается!
Хочешь разобраться в работе пресловутого
протокола ICMP, о котором все так много говорят? Да, понимаю,
читать толстенные книги по протоколам, в которых понятны только предлоги, или еще хуже - красными глазами читать RFC, держа перед собой толстенный англо-русский словарь, так как твои познания в английском заканчиваются фразой:
"Who`s on duty today? I am on duty today." - кому хочется?! Ты прекрасно знаешь, что самый верный путь к знаниям - это практика.
Когда ты видишь как формируются пакеты, как они отправляются, ты сможешь в дальнейшем понять и более сложные вещи! Но у тебя гигантская проблема - Windows 9x!
К сожалению работать с пакетами на низком уровне
winsock (библиотека предоставляющая интерфейс работы с сокетами) в этих версиях
(9х) не позволит! Есть несколько способов решения этой проблемы: ставь другую ось
(или старшие версии Windows 2000, XP...) или ищи NDIS драйвер и учись его использовать
(можешь, конечно, сам его написать, но если ты его написал, то зачем тебе читать все это). Но никто не запрещал тебе работать с протоколами высокого уровня.
Чтобы спуфить пакеты, например ICMP, нужно хотя бы знать как они выглядят и для чего вообще предназначены. Я предлагаю тебе инструмент, с помощью которого ты сможешь анализировать ICMP пакеты - а это достаточно важно!
Что тебе нужно для создания своего собственного анализатора ICMP пакетов:
компилятор какого-либо языка (реализующего
winsock, все функции описанные ниже практически не меняют своего интерфейса),
пальцы чтобы написать код, мозги чтобы все это понять.
Итак, начнем. Я написал все на С++ (Borland C++ v5.01). Сначала действуем по стандартному плану создания сервера: инициализируем структуру sockaddr_in таким образом:
sockaddr_in *addr;
addr = new sockaddr_in;
addr->sin_family = AF_INET; // Семейство адресов AF_INET или PF_INET - каму как нравится.
addr->sin_port = htons(0); // Номер порта нам неважен, мы работаем на низком уровне,
// где номера портов не имеют значение.
addr->sin_addr.s_addr = htonl(INADDR_ANY); // Выбираем любой интерфейс(обычно он один)
Затем инициализируем структуру protoent, чтобы winsock знал с каким протоколом мы будем работать:
protoent *protocol;
protocol = getprotobyname("icmp");
Создаем дескриптор сокета:
int sock;
sock = socket(AF_INET,SOCK_RAW,protocol->p_proto);
Обрати внимание, что мы работаем не с SOCK_DGRAM, и уж тем более не с SOCK_STREAM, а с SOCK_RAW, так называемые "сырые" сокеты. Затем, как обычно, проверяем на ошибки и идем далее
(если INVALID_SOCKET, то обломись дружок). Биндим наш сокет с
адресом, которой мы определили в указателе addr:
int err;
err = bind(sock,(sockaddr *)addr,sizeof(*addr));
Тоже проверяем на ошибки. Дальше начинается самое интересное: мы не вызываем функции listen() и
accept(), как обычно, а сразу начинаем принимать пакеты функцией recvfrom():
int rc;
char buffer[1024];
while(true)
{
rc = recvfrom(sock,buffer,sizeof(buffer),0,(sockaddr *)addr,&len);
}
Проверяем на ошибки, если rc == -1 тогда ошибка, иначе все круто
и идем дальше (все это делается внутри бесконечного цикла).
Когда мы получили пакет из сети, в структуре addr у нас хранится
адрес того хорька, который послал тебе этот ICMP пакет, только не в привычном для нас виде
("четыре точки"), а в машинном. Надо привести его к читаемому виду.
Легко!
cout<<"received from: "<<inet_ntoa(addr->sin_addr)<<endl;
Теперь у нас в руках полученный пакет (в массиве buffer). Что с ним делать? Организуем процедуру для вывода содержимого пакета на экран. Я особо не заморачивался по поводу этой процедуры, так что кому не
нравиться может организовать все самостоятельно. Главное знать, что где находиться!
Теперь о некоторых нюансах. Прежде всего как узнать ось по пингу? Конечно, точно ось не определить, но если тебя пингуют стандартными прогами, входящими в пакет ОС
(ping...) с размером пакета по дефолту, можно точно сказать: если тебе пришло 32 байта,
то знай - это твой товарищ по Виндам, если 56, то это
обладатель UNIX машины!
Если поле тип содержит 0 или 8, то знай - это ping . Если
5 - запрос на переадресацию (советую тщательно изучить именно этот тип ICMP,
так как он бывает очень полезен при проведении некоторых видов атак!).
Если ты все сделаешь, откомпилишь и запустишь, затем
пропингуешь самого себя, ты получишь столько пакетов сколько отправил! Почему, спросишь ты? Дело в том что "сырым" сокетам передаются не все ICMP пакеты, некоторые ядро обрабатывает самостоятельно, это небольшой недостаток нашей с тобой проги.
Зато если вместо IPPROTO_ICMP в сокете написать IPPROTO_RAW, тогда ты получишь доступ и к IGMP пакетам, а также ко всем пакетам в поле протокол которых стоит неизвестное ядру значение, попросту говоря все пакеты, которые ядро не знает как обрабатывать!
С вопросами можете обращаться по адресу alpon83@mail.ru, помогу чем смогу!