- •Лабораторная работа №1
- •1.1. Цель и содержание работы
- •1.2. Основные конструкции языка c
- •Int X; // Переменная типа int
- •Int list[20]; // Массив целых величин
- •If (условие) оператор1 else оператор2
- •1.3. Функции ввода-вывода языка с
- •1.4. Создание консольного приложения
- •1.5. Меню интегрированной среды
- •1.6. Компиляция, отладка и запуск программы
- •1.7. Упражнения
- •Лабораторная работа №2
- •2.1. Цель и содержание работы
- •2.2. Использование функций библиотеки ipHlpApi
- •2.3. Упражнения
- •Int iErr; // Код ошибки
- •Лабораторная работа №3
- •3.1. Цель и содержание работы
- •3.2. Библиотека функций Winsock2
- •3.3. Структуры данных для работы с сокетами
- •3.4. Приложение-сервер
- •3.5. Приложение-клиент
- •3.6. Упражнения
- •Лабораторная работа №4
- •4.1. Цель и содержание работы
- •4.2. Функции для работы по протоколу udp
- •4.3. Приложение-сервер
- •4.4. Приложение-клиент
- •4.5. Упражнения
- •Лабораторная работа №5
- •5.1. Цель и содержание работы
- •5.2. Сканирование портов
- •5.3. Функции для определения состояния портов
- •5.4. Упражнения
- •Лабораторная работа №6
- •6.1. Цель и содержание работы
- •6.2. Сниффер
- •6.3. Упражнения
- •Библиографический список
5.4. Упражнения
Требуется последовательно выполнить следующие действия:
Создать консольное приложение, ввести, скомпилировать и запустить программу, приведенную в листинге 5.2 (перед началом компиляции в свойствах проекта в разделе Linker/Input в пункте Additional Dependencies добавить библиотеки IPHlpApi.lib и ws2_32.lib). Отображенные в окне программы номера открытых портов нужно запомнить или записать, а затем завершить работу программы нажатием клавиши Enter.
Создать новое консольное приложение, ввести, скомпилировать и запустить программу-сканер, приведенную в листинге 5.1 (перед началом компиляции в свойствах проекта в разделе Linker/Input в пункте Additional Dependencies добавить библиотеку ws2_32.lib). В качестве IP-адреса нужно указать петлевой адрес 127.0.0.1. Начальное и конечное значения диапазона адресов сканируемых портов следует задать таким образом, чтобы в него попадало несколько открытых портов. После окончания сканирования завершить работу программы нажатием клавиши Enter.
Запустить сканер портов повторно, указав IP-адрес соседнего компьютера и тот же диапазон адресов портов, который был задан в предыдущем пункте. После окончания сканирования завершить работу программы нажатием клавиши Enter.
Лабораторная работа №6
6.1. Цель и содержание работы
Целью работы является изучение правил использования сырых сокетов библиотеки Winsock2 для прослушивания сетевого трафика.
Отчет о лабораторной работе не оформляется. Прием задания производится непосредственно на компьютере по предъявлению работающей, полностью отлаженной программы.
6.2. Сниффер
Сниффер (sniffer) – это программа, позволяющая просматривать сетевой трафик в пределах данного сегмента сети. Ее возможности основаны на особенностях протокола Ethernet: все устройства используют единую магистраль для обмена данными. Каждое устройство имеет уникальный MAC-адрес длиной 6 байт. В заголовке кадра Ethernet указывается MAC-адрес отправителя и MAC-адрес получателя. Устройства сетевого обмена ретранслируют этот кадр на все устройства в данном сегменте сети. Сетевая плата обычно принимает только пакеты, адрес получателя в которых совпадает с ее адресом, и отсеивает все остальные.
Для создания сниффера необходимо, во-первых, каким-то образом получить доступ к сетевому трафику. Т.к. сетевая плата по умолчанию игнорирует пакеты, не предназначенные для нее, то необходимо перевести ее в состоянии полного прослушивания (promiscuous mode). Для переключения в режим прослушивания используется функция управления режимом ввода-вывода int ioctlsocket(SOCKET s, long cmd, u_long* argp), которая имеет три параметра: дескриптор сокета, код команды и указатель на параметр команды. Код команды для включения прослушивания имеет значение 0x98000001.
Во-вторых, необходимо иметь некий набор правил и фильтров, согласно которым из общего сетевого потока будут выбираться необходимые пакеты. В большинстве случаев нет нужды просматривать все идущие через сеть пакеты – как правило, владелец машины, на которой запущен сниффер, желает просматривать трафик только одного типа или от одного устройства. Для обеспечения доступа к информации, передаваемой в заголовках пакетов, используются сырые (RAW) сокеты: при открытии сокета второй параметр функции socket должен иметь значение SOCK_RAW.
В-третьих, необходимо выбрать внешний интерфейс программы. Получаемые пакеты можно либо просто выводить на экран, либо сохранять на жесткий диск для дальнейшего анализа. Пример программы-сниффера приведен в листинге 6.1. В этом примере на экран выводится только информация, содержащаяся в заголовках пакетов.
Листинг 6.1. Сниффер
#include "stdafx.h"
#include <conio.h>
#include <winsock2.h>
#define MAX_PACKET_SIZE 0x10000
#define SIO_RCVALL 0x98000001
// Буфер для приёма данных
char Buffer[MAX_PACKET_SIZE]; // 64 Kb
//Структура заголовка IP-пакета
typedef struct IPHeader {
UCHAR iph_verlen; // Версия и длина заголовка
UCHAR iph_tos; // Тип сервиса
USHORT iph_length; // Длина пакета
USHORT iph_id; // Идентификатор
USHORT iph_offset; // Флаги и смещения
UCHAR iph_ttl; // Время жизни пакета
UCHAR iph_protocol; // Протокол
USHORT iph_xsum; // Контрольная сумма
ULONG iph_src; // IP-адрес отправителя
ULONG iph_dest; // IP-адрес назначения
} IPHeader;
int main(int argc, _TCHAR* argv[])
{
WSADATA wsadata;
SOCKET s; // Сокет
char name[128]; // Имя хоста (компьютера)
HOSTENT* phe; // Информация о хосте
SOCKADDR_IN sa; // Адрес хоста
IN_ADDR sa1;
unsigned long flag = 1; // Флаг PROMISC
unsigned short lowbyte; // Младший байт размера пакета
unsigned short hibyte; // Старший байт размера пакета
// Инициализация
WSAStartup(MAKEWORD(2,2), &wsadata);
s = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
gethostname(name, sizeof(name));
phe = gethostbyname(name);
ZeroMemory(&sa, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr =
((struct in_addr *)phe->h_addr_list[0])->s_addr;
bind(s, (SOCKADDR *)&sa, sizeof(SOCKADDR));
// Включение promiscuous mode.
ioctlsocket(s, SIO_RCVALL, &flag);
// Цикл приёма IP-пакетов (продолжается до тех пор,
// пока не нажата любая клавиша на клавиатуре).
while(!_kbhit())
{
int count;
count = recv(s, Buffer, sizeof(Buffer), 0);
// обработка IP-пакета
if(count >= sizeof(IPHeader))
{
IPHeader* hdr = (IPHeader *)Buffer;
// Преобразуем в понятный вид адрес отправителя.
printf("Packet: From ");
sa1.s_addr = hdr->iph_src; printf(inet_ntoa(sa1));
// Преобразуем в понятный вид адрес получателя.
printf(" To ");
sa1.s_addr = hdr->iph_dest;
printf(inet_ntoa(sa1));
// Определяем протокол (только для TCP и UDP).
printf(" Prot: ");
if(hdr->iph_protocol == IPPROTO_TCP) printf("TCP ");
else
if(hdr->iph_protocol == IPPROTO_UDP)
printf("UDP ");
else printf("??? ");
// Вычисляем размер пакета (меняем байты местами)
lowbyte = hdr->iph_length>>8;
hibyte = hdr->iph_length<<8;
hibyte = hibyte + lowbyte;
printf("Size: %u",hibyte);
// Выводим время жизни пакета.
printf(" TTL: %u\n",hdr->iph_ttl);
}
}
closesocket(s);
WSACleanup();
}