Технологии сетевых коммуникаций. Учебно-методическое пособие
.pdf
|
Продолжение табл. П4 |
|
-i, --in-interface |
Критерий |
|
Пример |
iptables -A INPUT -i eth0 |
Описание |
Интерфейс, с которого был получен пакет. Допускается только в |
|
цепочках INPUT, FORWARD и PREROUTING. Если имя интер- |
|
фейса завершается символом +, то критерий задает все интерфей- |
|
сы, начинающиеся с заданной строки, например -i PPP+ обознача- |
|
ет любой PPP интерфейс, а запись -i ! eth+ -- любой интерфейс, |
|
кроме любого eth |
Критерий |
-o, --out-interface |
Пример |
iptables -A FORWARD -o eth0 |
|
Задает имя выходного интерфейса |
Описание |
|
|
-f, --fragment |
Критерий |
|
Пример |
iptables -A INPUT -f |
Описание |
Правило распространяется на все фрагменты фрагментированного |
|
пакета, кроме первого |
Критерий |
--sport, --source-port |
|
iptables -A INPUT -p tcp --sport 22 |
Пример |
|
|
Исходный порт, с которого был отправлен пакет. В качестве па- |
Описание |
|
|
раметра может указываться номер порта или название сетевой |
|
службы, а также интервал: 22:80 |
Критерий |
--dport, --destination-port |
|
Порт назначения |
Описание |
|
|
iptables -p tcp --syn |
Критерий |
|
|
Распространяется на пакеты попыток соединений ( установлен |
Описание |
|
|
флаг tcp –syn) |
Критерий |
--tcp-option |
|
iptables -p tcp --tcp-option 16 |
Пример |
|
|
Опции пакета |
Описание |
|
|
--sport, --source-port |
Критерий |
|
|
iptables -A INPUT -p udp --sport 53 |
Пример |
|
|
Исходный порт, с которого был отправлен пакет. В качестве па- |
Описание |
|
|
раметра может указываться номер порта или название сетевой |
|
службы, а также интервал: 22: |
|
Инверсия разрешена |
|
41 |
|
Окончание табл. П4 |
|
--dport, --destination-port |
Критерий |
|
|
Порт назначения |
Описание |
|
|
--icmp-type |
Критерий |
|
|
iptables -A INPUT -p icmp --icmp-type 8 |
Пример |
|
|
Тип сообщения ICMP Тип сообщения ICMP определяется номе- |
Описание |
|
|
ром или именем. Числовые значения определяются в RFC 792. |
|
Чтобы получить список имен ICMP значений выполните команду |
|
iptables --protocol icmp --help |
|
|
Действие:
ACCEPT – принять
DROP – сбросить
REJECT – отклонить LOG – запротоколировать
Gnupg – утилита PGP шифрования и создания электронных подписей
Генерация ключа:
[user@mdk]$ gpg --gen-key
Экспорт ключа:
gpg -armor –export –i UID > myopen.asc
Импорт ключа
Открытый ключ может быть добавлен к вашей связке при помощи команды import:
gpg --import newkey.asc
Проверка отпечатка
Достоверность импортированного ключа должна быть подтверждена при помощи отпечатка:
gpg –fingerprint
42
Экспорт ключа на сервер ключей
Отпечатки ключа проверяются его владельцем. Можно сразу поместить ключ на сервер:
gpg --send-keys --keyserver wwwkeys.pgp.net
Подписывание ключа
gpg --edit-key -i UID (переходит в командный режим) sign
Посмотреть цепочку подписей: gpg --list-sigs.
Ключ также можно указать путем явной ссылки на него через
UUID (–u)
Создание электронной подписи:
gpg --clearsign -a test.file - создает подпись
Проверка электронной подписи gpg --verify test.file.asc
Шифрование файла
gpg -ea –r email@ngs.ru test.file - зашифровать
Дешифрование файла
gpg -d test.file.asc >test.file расшифровать
Список литературы
1.Руководство по Iptables Iptables Tutorial 1.1.14 http://www.linuxsecurity.com/resource_files/firewalls/IPTables- Tutorial/iptables-tutorial.html
2.Шнайер Б. Прикладная криптография. Протоколы, алгоритмы, исход-
ные тексты на языке Си. – М.: Изд-во ТРИУМФ, 2002. – 816 с.: ил.
3.Салома А. Криптография с открытым ключом. – М.: Мир, 1995. – 318 с.
4.http://help.ubuntu.ru/wiki/iptables.
43
ЛАБОРАТОРНАЯ РАБОТА № 4
Разработка сетевого приложения на языке Си
Цель работы: знакомство с методами обмена данными при помощи классических сокетов. Разработка приложения, способного обмениваться данными по UDP в сетях IPv4 и IPv6. Знакомство с программированием на языке Си в системе Linux.
1. Краткие теоретические сведения
Сокет – конечная точка сетевых соединений в стеке протоколов TCP-IP. Процесс любого обмена данными по сети в многозадачной операционной системе сводится к тем или иным операциям с сокетами. Сокет – это точка входа в приложение, осуществляющее обмен данными в сети. Так, если пара IP адрес/ маска (или только адрес в сетях IPV6) однозначно определяет узел в сети, то сокет – приложение, которое готово обмениваться данными. Существует три режима операций с сокетами:
блокирующиеся сокеты;
асинхронные сокеты;
низкоуровневые сокеты.
Операции, которые потребуются для объявления сокета и привязки его к процессу, зависят от типа протокола, с помощью которого предполагается организовать соединение. Так, протокол TCP, как наиболее сложный, потребует создания соединения «точка-точка», в котором будут активно участвовать две оконечные точки, способные работать в двух режимах:
режим сервера;
режим клиента.
Для создания TCP сокета на языке Си потребуется следующее.
Выполнить инициализацию объекта «Сокет»
44
#include <sys/types.h> #include <sys/socket.h>
int socket(int domain, int type, int protocol);
Domain — пространство имен и протоколов:
IPV,4 IPV6, loopback.
Наиболее часто используются:
AF_UNIX(AF_LOCAL) — Фс ОS Unix- «локальный сокет» - обмен данными через специальный объект ФС
AF_INET — обмен данными через сетевой стек (в т.ч. Через loopback)
AF_PACKET — низкоуровневый обмен
Выполнить объявление сокета
int socket(int domain, int type, int protocol);
Type — указывает способ обмена данными по сети SOCK_STREAM — протокол TCP, требуется установка соедине-
ния. Может быть использован, только если взаимодействующая сторона SOCK_STREAM с назначаемым IP адресом
SOCK_DGRAM — протокол UDP, не требует соединения, допус-
кает multicast, brodcast,network адреса
SOCK_RAW — низкоуровневое формирование ip. Возможна обработка icmp.
Дополнительно через ||
SOCK_NONBLOCK – неблокирующий сокет – точка для обслуживания нескольких клиентов из одного треда
Заполнить структуру с адресом и выполнить привязку соке-
та к IP адресу и порту
#include <sys/types.h> #include <sys/socket.h>
int bind(int sockfd, struct sockaddr *addr, int addrlen);
Sockfd – дескриптор сокета, то,что вернула команда socket на предыдущем шаге.
45
struct sockaddr {
unsigned short sa_family; // Семейство адресов, AF_xxx char sa_data[14]; // 14 байтов для хранения адреса
};
sa_family – идентификатор домена, аналогичный первому параметру функции socket.
Адрес sa_data -> – указатель на структуру
struct sockaddr_in { |
|
|
short int |
sin_family; // Семейство адресов |
|
unsigned short int sin_port; |
// Номер порта |
|
struct in_addr |
sin_addr; |
// IP-адрес |
unsigned char |
sin_zero[8]; // "Дополнение" до размера струк- |
|
туры sockaddr };
Адрес перевернут младшим «вперед», struct in_addr {
unsigned long s_addr;
};
Следовательно, потребуются преобразование порядка следования байт в словах.
Существует два формата представления адреса: порядок «хо-
ста» (host byte order) и «сетевой»(net byte order), отличающиеся по-
рядком следования старших/младших байт в слове. В сокете API используется сетевой порядок следования, поэтому требуется преобразование.
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong); uint16_t htons(uint16_t hostshort); uint32_t ntohl(uint32_t netlong); uint16_t ntohs(uint16_t netshort);
Для создания серверного сокета потребуется:
создать очередь запросов на соединение. Сокет прослушивает порт и ожидает нового соединения:
int listen(int sockfd, int sizeoflisten);
sockfd – знакомый нам дескриптор сокета
46
int sizeoflisten – длина очереди. 1 – всего один клиент сможет подключиться параллельно к сокету
0 – все в порядке – новое соединение готово принимать данные. -1 произошла ошибка.
Сервер готов обслужить сокет — выполняется функция accept
#include <sys/socket.h>
int accept(int sockfd, void *addr, int *addrlen);
В структуру void *addr будет записан адрес клиента, который установил соединение.
int accept(int sockfd, null, null); – нам совершенно не интересно
«кто». Возврат — дескриптор, с которым можно делать send и receive или -1
На стороне клиентского сокета потребуется:
int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
где все структуры и параметры нам уже знакомы. Возврат – дескриптор для read и wrire или -1.
Если не связывать по bind — клиентский сокет автоматически получит номер из пространства 1024-65535. Однако можно привязать и его, если это необходимо.
Обмен данными с сокетами
Отправка данных
int send(int sockfd, const void *msg, int len, int flags);
flags – манипулирование флагами пакета (например, TOS). Может быть NULL
Возврат – количество байт, или -1.
Функция send отправит только то количество байт, которое сможет и совершенно не обязана отправить весь буфер одной посылкой. Возврат 0 не является ошибкой.
Пример функции, которая корректно отправляет данные в сокет: int sendallbuf(int s, char *buf, int len, int flags)
{
47
int total = 0; int n;
while(total < len)
{
n = send(s, buf+total, len-total, flags); if(n == -1) { break; }
total += n;
}
If(n==-1) return -1; else return total;
}
Получение данных
int recv(int sockfd, void *buf, int len, int flags);
Возврат: -1, если ошибка Возврат: 0, если соединение завершено
Возврат: количество прочитанных байт
Особенность recv – программа «останавливается» на этом операторе и ожидает получения «len» байт из сокет.
while(1)
{
bytes_read = recv(sock, buf, 1024, 0); if(bytes_read <= 0) break; send(sock, buf, bytes_read, 0);
}
В случае работы в режиме «сырого сокета» для обмена данными используется:
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
48
Реализация сокета, соответсвующего стандарту IPv6, потребует изменений:
Структура sockaddr превращается в sockaddr_in6: struct in6_addr {
union {
uint8_t u6_addr8[16]; uint16_t u6_addr16[8]; uint32_t u6_addr32[4];
} in6_u;
#define s6_addr |
in6_u.u6_addr8 |
#define s6_addr16 |
in6_u.u6_addr16 |
#define s6_addr32 |
in6_u.u6_addr32 |
}; |
|
struct sockaddr_in6 { |
|
sa_family_t sin6_family; |
/* AF_INET6 */ |
in_port_t sin6_port; |
/* Порт транспортного уровня # */ |
uint32_t sin6_flowinfo; |
/* IPv6 flow information */ |
struct in6_addr sin6_addr; /* IPv6 address */ |
|
uint32_t sin6_scope_id; |
/* IPv6 scope-id */ |
}; |
|
Фактически при разработке кода можно подменить все элементы структур, характерных для IPv4 на IPv6. Однако для разработки совместимых на уровне кода приложений в будущем рекомендуется использовать универсальную структуру sockaddr_storage,
/* Structure large enough to hold any socket address (with the historical exception of
AF_UNIX). 128 bytes reserved. */
#if ULONG_MAX > 0xffffffff
#define __ss_aligntype __uint64_t #else
#define __ss_aligntype __uint32_t #endif
#define _SS_SIZE |
128 |
#define _SS_PADSIZE |
(_SS_SIZE - (2 * sizeof (__ss_aligntype))) |
|
49 |
struct sockaddr_storage |
|
{ |
|
sa_family_t ss_family; |
/* Address family */ |
__ss_aligntype __ss_align; /* Force desired alignment. */ char __ss_padding[_SS_PADSIZE];
};
2. Методические указания для выполнения работы
Создайте файл с текстом программы на Си в любом текстовом редакторе, выполняющий действия, согласно варианту.
Откомпилируйте программу при помощи компилятора GNU
GCC:
gcc ./yourprog.c -o ./yourprog.bin
Выполните отладку программы.
Запротоколируйте сетевой обмен (tcpdump) и приведите его в
отчет.
В процессе выполнения работы пользуйтесь справкой man <функция>.
В случае досрочного выполнения задания рекомендуется незамедлительно переходить к выполнению лабораторной работы № 6.
3. Варианты задания
Для всех вариантов разработать программу, которая создаст UDP сокет и отправит данные на IP-адрес, указанный преподавателем, UDP пакет следующего содержания:
0-й байт: фиксирован и равен 129
1-й байт: день месяца
2-й байт: месяц
3-й байт: номер вашей бригады 4-й–40-й байт: латинскими буквами фамилия 1-го члена бригады
(sprintf(&buf[6], "…") )
41-й–60-й байт: латинскими буквами фамилия 2-го члена бригады 61-й–80-й байт: латинскими буквами фамилия 3-го члена бригады 81-й байт: сумма по «исключающему или» всех байт посылки
50
