Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Гараев Р.А. Программирование WinSock.doc
Скачиваний:
70
Добавлен:
02.05.2014
Размер:
765.44 Кб
Скачать

Сырые сокеты

Помимо потоковых и дейтаграммных сокетов существуют, так называемые сырые (RAW) сокеты. Они предоставляют возможность "ручного" формирования TCP/IP-пакетов, равно как и полного доступа к содержимому заголовков полученных TCP/IP-пакетов, что необходимо многим сетевым сканерам, FireWall'ам, брандмауэрам и, разумеется, хакерским программам, например, устанавливающим в поле "адрес отправителя" адрес самого получателя. Спецификация Winsock 1.x категорически не поддерживала сырые сокеты. В Winsock 2.x положение как будто было исправлено: по крайней мере, формально такая поддержка появилась и в SDK даже входил пример, демонстрирующий использование сырых сокетов для реализации утилиты ping. Однако, попытки использования сырых сокетов для всех остальных целей проваливались - система игнорировала сформированный "вручную" IP- (или TCP-) пакет и создавала его самостоятельно.

Документация объясняла, что для самостоятельной обработки заголовков пакетов, опция IP_HDRINCL должна быть установлена. Проблема в том, что вызов setsockopt(my_sock,IPPROTO_IP, IP_HDRINCL, &oki, sizeof(oki)) возвращал ошибку!

Таким образом, на прикладном уровне получить непосредственный доступ к заголовкам TCP/IP невозможно. Это препятствует переносу многих приложений из UNIX в Windows, более того - определенным образом ущемляет возможности самой Windows, не позволяя ей решать целый ряд задач, требующих поддержки сырых сокетов.

Разработка и тестирование учебных примеров

В процессе выполнения лабораторной работы предполагается разработка на основе выданных преподавателем заготовок четырех программ, реализующих простые UDP и TCP эхо-серверы и UDP- и TCP- клиенты. (Эхо-сервер просто возвращает клиенту полученные от него же данные).

Проверка работоспособности UDP-сервера и клиента: запустите UDP-сервер и одну или несколько копий клиента - в каждой из них можно набирать на клавиатуре некоторые данные и получать их обратно от сервера.

Внимание: работая с серверными приложениями, вы (если не предпримете дополнительных мер) предоставляете возможность воспользоваться ими каждому абоненту Интернет (если в момент работы сервера вы подключены к Интернет). Проблема в том, что ошибки реализации, в особенности переполняющиеся буфера, могут позволить удаленному злоумышленнику выполнить на вашей машине любой код, со всеми вытекающими отсюда последствиями.

Будьте очень внимательны, а еще лучше не входите в Интернет, пока не будете полностью уверены, что сервера отлажены и не содержат ошибок!

Программирование IPX/SPX сокетов

 Когда говорят о сокетном программировании, чаще всего подразумевается стек TCP/IP. Однако, как указывалось выше, и с другими протокольными стеками работа может вестись с использованием WinSocket. Рассмотрим пример протоколов IPX/SPX. Многие программные модули и системы используют их до сих пор

( Подробнее ознакомиться и прочитать об этих протоколах можно здесь: http://www.sources.ru/protocols/bsp08/index.html).

Все начинается, как всегда, с инициализации WINSOCK библиотеки, обработка ошибок ниже отброшена для упрощения понимания кода: #include <winsock.h> // прототипы функций библиотеки #include <wsipx.h> // IPX/SPX структуры #include <wsnwlink.h> // IPX/SPX структуры и константы для NT платформ void main () { WSADATA wsaData; // требуемая версия winsock.dll библиотеки WORD wVersionRequested = MAKEWORD( 1, 1 ); // инициализация winsock.dll WSAStartup( wVersionRequested, &wsaData ); // собственно работа с сокетами ……………… WSACleanup( ); // в заключение сообщаем системе, что работа с winsock.dll завершена

}

Конкретные примеры работы с сокетами приведены ниже:

WORD SPX_SOCKET = 0x5647 char localNetNum[IPX_NET_SIZE];  char localNodeNum[IPX_NODE_SIZE]; // открытие сокета SOCKET spx_skt = socket (PF_IPX, SOCK_STREAM, NSPROTO_SPX)); // проверим если открылся  if (spx ==INVALID_SOCKET) MessageBox (NULL, “Ошибка открытия сокета.”, "Error", MB_OK); // структура для адреса нашего сокета sockaddr_ipx addr_ipx; /* так выглядит структура sockaddr_ipx в WSIPX.H typedef struct sockaddr_ipx { u_short sa_family; u_char sa_netnum[4];

u_char sa_nodenum[6]; unsigned short sa_socket;

} SOCKADDR_IPX, *PSOCKADDR_IPX, FAR *LPSOCKADDR_IPX */

int sz = sizeof (addr_ipx); // обнулим её memset (&addr_ipx, 0, sz); addr_ipx.sa_family = AF_IPX; // тип протокола addr_ipx.sa_socket = htons(SPX_SOCKET); // номер сокета // привязываем его к номеру сокета bind(spx_skt, (sockaddr*) &addr_ipx, sz); // узнаем наш адрес getsockname (spx_skt, (sockaddr*) &addr_ipx, &sz);  // наш номер сети memcpy (localNetNum, addr_ipx.sa_netnum, IPX_NET_SIZE); // наш номер узла memcpy (localNodeNum, addr_ipx.sa_nodenum, IPX_NODE_SIZE);

В остальном, работа с SPX идентична работе TCP сокетов. Все написанное выше справедливо и для IPX сокетов, за исключением того, что последние не могут быть использованы для операции connect. Открываются они следующим образом:

SOCKET ipx_skt = socket (PF_IPX, SOCK_DGRAM, NSPROTO_IPX); Передача данных происходит следующим образом: // структура для хранения удалённого адреса sockaddr_ipx addr_ipx;

// обнуляем её, хотя это не всегда нужно, но и никогда не мешает memset (&addr_ipx, 0, sizeof (addr_ipx)); // тип протокола addr_ipx.sa_family = AF_IPX; // номер сокета addr_ipx.sa_socket = htons(SOCKET_NR); // удалённый номер сети memcpy (addr_ipx.sa_netnum, remoteNetNum, IPX_NET_SIZE); // удалённый номер узла memcpy (addr_ipx.sa_nodenum, remoteNodeNum, IPX_NODE_SIZE); char* buff = “Test string”; // вот и собственно передача данных sendto (ipx_skt, buff, strlen (buff), 0, (sockaddr*)&addr_ipx, sizeof (addr_ipx)); Дальше следуют некоторые полезные сведения о работе с данными протоколами. Широковещательные пакеты

Широковещательные пакеты могут быть использованы, например, в качестве средства поиска клиентом сервера, в случае, когда известен порт (сокет IPX) нужного сервера, но не известен его сетевой адрес.

sockaddr_ipx addr_ipx; char* broadcast_msg = “Кое-что для передачи в широковещательном режиме”; SOCKET ipx_skt = socket (PF_IPX, SOCK_DGRAM, NSPROTO_IPX); addr_ipx.sa_family = AF_IPX; // номер сокета, данный номер используется при посылке SAP пакетов в Netware addr_ipx.sa_socket = htons (0x0452); // = IPXSKT_SAP // для широковещательных пакетов memset (addr_ipx.sa_netnum, 0, IPX_NET_SIZE); memset (addr_ipx.sa_nodenum, 0xff, IPX_NODE_SIZE); // устанавливаем флаг для посылки широковещательных пакетов int set_broadcast = 1; setsockopt (ipx_skt, SOL_SOCKET, SO_BROADCAST, (char*)& set_broadcast, sizeof (set_broadcast)); //собственно само широковещание sendto (ipx_skt, broadcast_msg, strlen (broadcast_msg), MSG_DONTROUTE, (sockaddr*)&addr_ipx, sizeof (addr_ipx));

Установка, изменение DataStreamType в заголовке SPX пакета

Это в принципе может быть использовано в собственных целях, например для искусственной сегментации своих данных для совместимости разных реализаций протокола. Например, некоторые реализации протокола для ДОС поддерживают максимальную длину пакета в 512 байт, либо принудительно ограниченную сетевыми модулями, они и используют DataStreamType, чтобы указать последнюю порцию данных.

Устанавливается следующим образом: // Можно использовать любое значение между 0 - 0xfd // следующие значения зарезервированы // #define SPX_HANG_UP 0xFE // #define SPX_HANG_UP_ACK 0xFF int stream_type = 0x05; setsockopt (spx_skt, NSPROTO_IPX, IPX_DSTYPE, (char*)&stream_type, sizeof(stream_type);

Причём данную установку надо делать перед каждым send. Работает нормально при посылке данных ДОС клиенту, а при приеме пакетов WIN клиентом от ДОС клиента DataStreamType не устанавливается, т.е. не получается установленное значение DataStreamType ДОС клиентом. Возможен обход данной проблемы при помощи следующего фрагмента кода:

int rcv; // количество принятых байтов за один recv int rcv_total = 0; // общее количество принятых байт do{ // прием данных rcv = recv (spx_socket, rd_buffer + rcv_total, MAX_BUF_SIZE - rcv_total, 0); if (rcv > 0) rcv_total += rcv; // если мы что-то получили }while (rcv > 0); // пока принимаются данные Данный метод хорош еще тем, что WIN клиент может принять один пакет вместо нескольких посланных ДОС клиентом. 

Другие специфические расширения для данных протоколов, применяемые с getsockopt/setsockopt, можно найти в файле wsnwlink.h, но данные расширения для NT платформ могут не работать для других реализаций данных протоколов.