Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

СПО_1 / СПО / Sozdanie.setevyh.prilojenii.v.srede.Linux

.pdf
Скачиваний:
80
Добавлен:
11.04.2015
Размер:
2.94 Mб
Скачать

8.В файле /etc/man.config добавьте в переменную среды MANPATH путе вое имя /usr/local/ssl/man, ссылающееся на каталог документации к библиотеке (возможно, потребуется запустить утилиту makewhatis).

9.Добавьте в переменную среды PATH путевое имя /usr/local/ssl/bin.

Впроцессе компиляции будут использоваться статические библиотеки, поэто^ му не удивляйтесь, если размер исполняемых файлов превысит 600 Кбайт. Чтобы сделать библиотеки совместно используемыми, следует поменять у файлов libssl.a и libcrypto.a расширение: вместо .а — .so.

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

cc test.с lssl lcrypto

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

Создание SSL$клиента

Итак, давайте попробуем написать связку клиент/сервер. Создать SSL клиент и SSL сервер так же просто, как и в случае обычных сокетов, так как библиотека OpenSSL основана на вызовах рассматривавшихся в предыдущих главах функций сокетов.

Первый шаг заключается в инициализации библиотеки OpenSSL: /*************************************************************/

/*** Инициализация клиента ***/

/**************************************************************/

SSL_METHOD «method;

 

 

 

 

 

 

SSL_CTX *ctx;

 

 

 

 

 

 

OpenSSL_add_all_algoritms();

/*

загружаем модули

шифрования

*/

SSL_load_error_strings(); /*

загружаем и

регистрируем

таблицы

 

 

 

 

 

сообщений

tf6

ошибках

*/

method

= SSLv2_client_method();

/* создаем новый

клиентский

 

 

 

 

 

 

 

метод

*/

ctx =

SSL_CTX_new(method);

 

./*

создаем новый контекст

*/

Если функции возвращают значение NULL или 0, следует вывести сообщение об ошибке:

ERR_print_errors_fp(stderr);

/* записываем сообщения

об

 

 

ошибках в поток stderr */

Далее создается традиционный сокет:

 

/***

Подключение клиентского сокета к SSL серверу

***/

struct sockaddr_in addr;

 

 

Глава 16. Безопасность сетевых приложений

321

Ⱦɚɧɧɚɹ ɜɟɪɫɢɹ ɤɧɢɝɢ ɜɵɩɭɳɟɧɚ ɷɥɟɤɬɪɨɧɧɵɦ ɢɡɞɚɬɟɥɶɫɬɜɨɦ %RRNV VKRS Ɋɚɫɩɪɨɫɬɪɚɧɟɧɢɟ ɩɪɨɞɚɠɚ ɩɟɪɟɡɚɩɢɫɶ ɞɚɧɧɨɣ ɤɧɢɝɢ ɢɥɢ ɟɟ ɱɚɫɬɟɣ ɁȺɉɊȿɓȿɇɕ Ɉ ɜɫɟɯ ɧɚɪɭɲɟɧɢɹɯ ɩɪɨɫɶɛɚ ɫɨɨɛɳɚɬɶ ɩɨ ɚɞɪɟɫɭ piracy@books-shop.com

struct hostent *host = gethostbyname(hostname);

:

*/

int sd = socket(PF_INET, SOCK_STREAM, 0);

/* создаем сокет

bzero(&addr, sizeof(addr));

 

 

 

addr.sin_family = AF_INET;

 

 

 

addr.sin_port = htons(port);

/*

серверный порт

*/

addr.sin_addr.s_addr = *(long*)(host >h_addr); /* адрес сервера

*/

connect(sd, &addr, sizeof(addr));

/* подключаемся к серверу

*/

После установления соединения между клиентом и сервером необходимо соз дать экземпляр объекта SSL и связать его с соединением:

у**********************************************************/

/***

Инициализируем протокол SSL и создаем

***/

/***

зашифрованный

канал

 

***/

/**********************************************************/

SSL *ssl = SSL_new(ctx);

/* создаем новое SSL соединение */

SSL_set_fd(ssl, sd);

/* подключаем дескриптор сокета */

if ( SSL_connect(ssl) == 1 ) /* устанавливаем соединение */

 

ERR_print_errors_fp(stderr);

/* сообщаем об

ошибках */

С этого момента имеется полностью зашифрованное SSL соединение. Полу чить набор шифров можно следующим образом:

char* cipher_name = SSL_get_cipher(ssl);

Можно также получить цифровые сертификаты: /***************************************************************/

/** Получение сертификатов ***/

/***************************************************************/

char

line[1024];

 

Х509

*х509 = X509_get_subject_name(cert);

/* имя владельца */

X509_NAME_oneline(x509, line, sizeof(line)); /* преобразование */

printf("Subject: %s\n", line);

 

x509 = X509_get_issuer_name(cert);

/* кем выдан */

X509_NAME_oneline(x509, line, sizeof(line)); /* преобразование */ printf("Issuer: %s\n", line);

Наконец, программы могут начать обмениваться данными с помощью функ ций, напоминающих вызовы send() и recv(). Но есть несколько отличий. Во первых, параметр flags отсутствует; во вторых, в случае ошибки возвращается — 1. В определении функций send() и recv() сказано, что при неудачном завершении они возвращают отрицательное значение.

/***************************************************************/

/***

Прием и отправка сообщений

int bytes;

bytes

= SSL_read(ssl, buf, sizeof(buf)); /* получаем/дешифруем */

bytes

= SSL_write(ssl, msg, strlen(msg)); /* шифруем/отправляем */

В библиотеке есть множество других функций для управления потоком, изме нения состояния соединения и конфигурирования сокетов.

322 Часть IV. Сложные сетевые методики

www.books-shop.com

Создание SSL сервера

Код клиента и сервера отличается лишь незначительно. В обоих случаях ини циализируется библиотека, устанавливается соединение и создается объект SSL. Но на сервере нужно выполнить несколько дополнительных действий. Прежде всего, немного отличается процедура инициализации:

/*** Инициализация сервера ***/

/**************************************************************/

SSL_METHOD «method;

 

 

 

 

 

 

SSL_CTX *ctx;

 

 

 

 

 

 

OpenSSL_add_all_algoritms();

/*

загружаем модули шифрования

*/

SSL_load_error_strings(); /*

загружаем

и

регистрируем

таблицы

 

 

 

 

 

сообщений об

ошибках

*/

method = SSLv2_server_method();

/*

создаем новый

серверный

 

 

 

 

 

метод */

ctx = SSL_CTX_new{method);

 

/*

создаем новый контекст

*/

Читатели, должно быть, обратили внимание на то, что используется протокол SSL2, а не SSL3. Это необходимо, если подключение к серверу осуществляется через броузер Netscape.

В отличие от клиента, сервер должен получить свой сертификат. Это осущест вляется в два этапа: сначала загружается файл сертификата, а затем — файл сек ретного ключа. Оба должны быть загружены в процессе инициализации. Как правило, и сертификат, и секретный ключ размещаются в одном и том же файле:

/*** Загружаем файлы сертификата и секретного ключа ***/

/************************************************************/

/* загружаем сертификат из файла */ SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM); /* загружаем секретный ключ из файла */ SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM); /* проверяем секретный ключ */

if ( !SSL_CTX_check_private_key(ctx) )

fprintf(stderr, "Key & certificate don't match");

Клиент также может загрузить файл сертификатов, но это не обязательно и зависит от используемой схемы безопасности.

Примечание

Как правило, чтобы иметь возможность распространять программное обеспечение в Internet, нужно купить сертификат у одного из центров сертификации, например фирмы VeriSign. Если же сертификаты нужны для целей отладки, их можно создать средствами библиотеки OpenSSL (не используйте сертификаты, поставляемые с библиотекой). Написанный на Perl сценарий CA.pl находится в каталоге /usr/local/ssl/misc, создаваемом при инсталляции библиотеки. Если сценарий не задает серию вопросов, значит, в переменной среды PATH не записан путь к ката логу /usr/local/ssl/bin.

Глава 16. Безопасность сетевых приложений

323

www.books-shop.com

Серверный сокет создается так же, как и клиентский:

/***

Конфигурируем серверный порт сокета

***/

struct sockaddr_in addr;

 

 

int sd, client;

 

 

sd = socket(PP_INET, SOCK_STREAM, 0);

/* создаем сокет */

bzero(&addr,

sizeof(addr));

 

 

addr.sin_family = AF_INET;

 

 

addr.sin_port = htons(port);

addr.sin_addr.s_addr = INADDR_ANY /* разрешаем любое сетевое

 

семейство */

bind(sd, &addr, sizeof(addr));

/* подключаемся к порту */

listen(sd, 10);

/* переходим в режим ожидания

*/

client accept(server, &addr, &len); /* принимаем запрос

*/

Как и в случае клиента, сервер должен создать объект SSL и связать его с кли ентским соединением:

/***

Создание SSL сеанса

***/

ssl = SSL_new(ctx);

 

/* создаем новое SSL соединение */

SSL_set_fd(ssl, client);

/* связываем сокет с соединением */

if ( SSL_accept(ssl)

== FAIL ) /* принимаем запрос по протоколу

 

ERR_print_errors_fp(stderr);

SSL

*/

 

 

else

 

 

 

 

{ int bytes;

 

 

 

 

bytes = SSL_read(ssl,

buf, sizeof(buf));

/* принимаем

 

 

 

 

сообщение

*/

SSL_write(ssl, reply,

strlen(reply));

/* посылаем ответ

*/

}

Описанные этапы действительно просты. Загрузите программу с нашего Web узла и попытайтесь подключиться к броузеру Netscape. Поскольку он не сможет распознать сделанный вами сертификат, появится предупреждающее сообщение и будет выдано несколько диалоговых окон для временной регистрации сертификата.

Резюме: безопасный сервер

Сокеты позволяют подключаться к самым разным компьютерам и создавать распределенные алгоритмы. Однако информация, которая передается между ком пьютерами, не скрыта от других компьютеров, подключенных к той же сети. Большинство компаний вынуждено представлять себя в Internet, так как это дик туется требованиями бизнеса. Но размещение конфиденциальной информации в Internet ведет к шпионажу, краже данных и их повреждению. Ответственность за это лежит на самой сети Internet.

Потери можно свести к минимуму, если заранее планировать обеспечение безопасности своих программных продуктов. Брандмауэры, системные политики

324 Часть IV. Сложные сетевые методики

www.books-shop.com

и шифрование — вот те средства, которые позволяют защитить Web сервер от нападений.

Когда два или несколько компьютеров взаимодействуют в открытой среде, такой как Internet, необходимы определенные протоколы и алгоритмы, уменьшающие вероятность шпионажа. Шифрование бывает различных видов и обеспечивает раз ный уровень безопасности. Два стандартных варианта шифрования — с открытым и с симметричным ключом. Оба этих метода применяются в современных комму никационных протоколах, в частности в SSL.

Существуют разные реализации функций SSL. На момент написания книги не было стандартной библиотеки таких функций. Но для языка С имеется открытая библиотека OpenSSL, которая обладает множеством возможностей и содержит более 200 функций. Применяя тщательное планирование и стандартные средства наподобие OpenSSL, можно создавать эффективные, надежные и безопасные программы, работающие в среде Internet.

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

Глава 16. Безопасность сетевых приложений

325

www.books-shop.com

Глава Широковещательная, групповая

17 и магистральная передача сообщений

В этой главе...

 

Широковещание в пределах домена

337

Передача сообщения группе адресатов

339

Резюме: совместное чтение сообщений

346

www.books-shop.com

Сеть — это среда передачи сообщений из одного места в другое. В сети при меняется множество различных технологий и имеются каналы с разной пропуск ной способностью. Но обычно недооценивают тот факт, что все компьютеры подключены к магистральной, или опорной, сети определенного типа. Как из влечь из этого преимущество?

Некоторые сообщения предназначаются нескольким адресатам одновременно. Вместо того чтобы отправлять одно и то же сообщение многократно, можно по слать одно сообщение, но заставить все заинтересованные компьютеры принять его. Тем самым сетевой трафик не будет "засоряться".

В протоколе IP предусмотрены два способа распределенной доставки сообще ний: широковещание и групповое вещание. В этой главе мы рассмотрим, как реализуются оба способа.

Широковещание в пределах домена

Первый режим распределенной доставки сообщений — широковещание [RFC919, RFC922] — основан на особенностях подсетей и применяющихся в них масок. Это принудительная форма доставки: все компьютеры в подсети должны получить сообщение. (На самом деле, если компьютер не поддерживает широко вещательный режим, сетевая плата откажется принять сообщение. Тем не менее сообщение занимает канал, и любой узел при желании сможет его прочитать.)

Пересмотр структуры IP адреса

Наличие подсети очень важно с точки зрения отправки и приема широкове щательных сообщений. Как описывалось в главе 2, "Основы TCP/IP", когда с помощью команды ifconfig конфигурируется сетевой интерфейс, задается также сетевая маска и широковещательный адрес. Последний — это специальный адрес, по которому компьютер ожидает поступления сообщений.

Границы подсети определяются сетевой маской и широковещательным адре сом. Например, если есть подсеть 198.2.56.X X X , в которую входят 250 узлов, то маской будет адрес 198.2.56.0, а широковещательный адрес будет таким: 198.2.56.255. (В главе 2, "Основы TCP/IP", упоминалось о том, что маска подсе ти, в принципе, может быть произвольной. Просто помните: последний знача щий бит задает границу маски.)

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

Послать широковещательное сообщение легче, чем принять его. Чтобы отпра вить сообщение, достаточно указать IP адрес получателя (сетевая подсистема впоследствии преобразует его в МАС адрес Ethernet платы принимающей сторо ны). А чтобы получить сообщение, сетевая плата должна прослушивать сеть, вы являя сообщения с заданным МАС адресом. Проблема заключается в том, что у широковещательного сообщения один адрес, а в подсети все компьютеры имеют разные МАС адреса.

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

Глава 17. Широковещательная, групповая и магистральная... 327

www.books-shop.com

Сетевая плата реагирует на сообщение, помещая его во внутренние буферы. По завершении операции плата уведомляет ядро, посылая ему запрос на прерывание. Ядро считывает пакет и проверяет IP адрес получателя. Если .он оказывается широ ковещательным адресом, ядро записывает пакет в очередь сетевой подсистемы.

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

Работа в широковещательном режиме

Включить широковещательный режим можно с помощью параметра сокета SO_BROADCAST. В остальном все остается прежним: программа создает обычный дейтаграммный сокет.

/*** Создание широковещательного дейтаграммного сокета ***/

const int on=l;

sd = socket(PF_INET, SOCK_DGRAM, 0);

if ( setsockopt(sd, SOL SOCKET, SO_BROADCAST, Son, sizeof(on))

1= 0 )

panic("set broadcast failed"); bzero(&addr, sizeof(addr)); addr.sin_family = AF_INET; addr.sin~port = htons(port); addr.sin~addr.s_addr = INADDR_ANY;

if ( bind(sd, Saddr, sizeof(addr)) != 0 ) panic)"bind failed");

addr.sin_port = htons(atoin(strings[2]));

if ( inet_aton(strings[1], Saddr.sin_addr) == 0 ) panic("inet_aton failed (%s)", strings[l]);

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

/*** Разделение обязанностей при отправке и приеме сообщений.

***/

/*** На отправляющей стороне входной канал закрывается.

***/

if ( fork() ) Receiver(sd);

else

{

shutdown(sd, SHUT RD); /* закрываем входной канал */

Sender(sd);

}

wait(O);

328

Часть IV. Сложные сетевые методика

www.books-shop.com

Ограничения широковещательного режима

Широковещательные сообщения имеют свои ограничения. В первую очередь следует отметить, что сообщение доставляется тольЦо компьютерам, входящим в подсеть. Правда, можно увеличить диапазон доставки, изменив щироковещатель ный адрес. Но широковещание в глобальной сети невозможно, так как адрес 255.255.255.255 больше недопустим в Internet. (Кроме того, большинство маршру тизаторов не позволяет широковещательным сообщениям проходить через них. Поэтому, даже если сообщению присвоен правильный широковещательный ад рес, к примеру 198.2.255.255, маршрутизатор, находящийся по адресу 198.2.1.0, может проигнорировать сообщение.)

Широковещательное сообщение доставляется всем компьютерам подсети. На аппаратном уровне широковещание реализовано так, что все сетевые платы будут получать сообщения. Это создает дополнительные неудобства тем компьютерам, которым такие сообщения в действительности не нужны.

Еще одной проблемой является протокол. В IPv4 широковещательная передача поддерживается только для дейтаграмм. Если необходима надежная потоковая дос тавка широковещательных сообщений, ее придется реализовать самостоятельно.

Передача сообщения группе

адресатов

Многоадресный режим [RFC1112] решает многие проблемы широковещатель ного режима. Идея широковещания заключается в доставке сообщения всем компьютерам в текущем диапазоне адресов. В многоадресном режиме устанавли ваются определенные групповые адреса, к которым подключаются компьютеры, желающие получать групповые сообщения.

Многоадресный режим имеет следующие преимущества перед широковещанием.

Поддержка всех необходимых протоколов. Можно осуществлять группо вую доставку как дейтаграмм, так и TCP пакетов. Что касается TCP, то такая поддержка еще не встроена в Linux, но можно найти свободно распространяемые библиотеки соответствующих функций.

Возможность группового вещания в глобальной сети. Можно подключаться к глобальным адресным группам. Правда, еще существуют зоны Internet, где не допускается групповая доставка сообщений.

Ограниченное число слушателей. Групповое вещание не обязывает все се тевые платы принимать сообщения (подробнее об этом — в разделе "Как реализуется многоадресный режим в сети").

Поддержка IPv6. В стандарте IPv6 широковещание не поддерживается во обще, а функции многоадресной доставки приняты и даже расширены.

Включение'поддержки многоадресного режима

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

Глава 17. Широковещательная, групповая и магистральная... 329

www.books-shop.com

Подключение к группе адресатов

Работать в многоадресном режиме так же просто, как подключаться к списку рассылки. Программа, присоединившаяся к адресной группе, будет получать все сообщения, публикуемые ее членами. Поэтому следует убедиться, что сущест вующий сетевой канал сможет справиться с потоком сообщений.

В главе 2, "Основы TCP/IP", говорилось о том, что в пространстве возможных IP адресов выделен диапазон адресов, зарезервированных для группового веща ния: 224.0.0.0 239.255.255.255. Этот диапазон, в свою очередь, подразделяется на более мелкие диапазоны, определяющие область видимости адреса, т.е. как дале

ко сможет дойти

сообщение, прежде чем

маршрутизатор блокирует его

(табл. 17.1).

 

 

Таблица 17.1. Диапазоны и области видимости групповых адресов

Область видимости

Число переходов (TTL)

Диапазон адресов

Кластер

О

224.0.0.0 224.0.0.255

Сервер

< 32

239.255.0.0 239.255.255.255

Организация

< 128

239.192.0.0 239.195.255.255

Глобальная сеть

<= 255

224.0.1.0 238.255.25.255

Чтобы подключиться к группе, необходимо вызвать функцию setsockopt(), передав ей в качестве параметра структуру ipjnreq:

/***************************************************************/

/*** Структура ipjnreq для задания группового адреса

struct ip_mreq

{

struct in_addr imrjnultiaddr; /* известная адресная группа */ struct in_addr imr_interface; /* сетевой интерфейс */

};

Поле imrjnultiaddr задает адресную группу, к которой необходимо присоеди ниться. Формат его такой же, как и у поля sin_addr структуры sockaddr_in. Поле imr_interface позволяет выбрать конкретный сетевой интерфейс узла. Это напо минает функцию bind(), которая делает то же самое, а если в качестве адреса указать константу INADDR_ANY, то сообщения будут приниматься через любой дос тупный интерфейс. Однако в многоадресном режиме эта константа имеет не сколько иной смысл.

Стандартный интерфейс группового вещания

Если в поле imr_interfасе присутствует константа INADDR_ANY, ядро самостоятельно выберет сетевой интерфейс. По крайней мере, в ядре Linux версий 2.2.хх эта константа не означает "прослушивать все сетевые интерфейсы". Поэтому, если в системе есть несколько сетевых уст ройств, подключаться к группе необходимо по каждому устройству в отдельности.

Следующий фрагмент программы иллюстрирует, как использовать структуру ipjnreq для подключения к группе. Поле imr_interface задано равным INADD_ANY исключительно в демонстрационных целях. Так можно делать только в том слу

330

Часть IV. Сложные сетевые методики

www.books-shop.com

Соседние файлы в папке СПО
  • #
    11.04.201527.19 Mб69Cpp4Unix.pdf
  • #
    11.04.201516.44 Mб52IP Arhitektura, protokoly, realizatsiya (vklyuchaya IP versii s IP Security).djvu
  • #
  • #
    11.04.201510.72 Mб51Стивенс. UNIX. Разработка сетевых приложений.djvu