Протокол ipv6 позволяет конфигурировать сеть без учатия пользователя с помощью icmpv6, если узел работает в качестве клиента(forwarding установлен в 0).
Поэтому возникает задача: как отследить эти изменения. Как оказывается, это достаточно просто, если использовать протокол netlink. Описание данного протокола можно найти здесь (eng) и здесь(рус.).
Для вывода информации об измененных маршрутах я создал функцию show_route. Вот ее исходный код:
маршрута. Поэтому общий вид пакета имеет следующий вид:
Таким образом, функция для выделения атрибутов:
Теперь можно написать main функцию:
Поэтому возникает задача: как отследить эти изменения. Как оказывается, это достаточно просто, если использовать протокол netlink. Описание данного протокола можно найти здесь (eng) и здесь(рус.).
Для вывода информации об измененных маршрутах я создал функцию show_route. Вот ее исходный код:
/*
buffer - хранит полученные сообщения от netlink
size - размер полученных данных
*/
void show_route(char *buffer, int size)
{
/*
nlmp - указатель на структуру заголовка netlink
routemsg - полезная нагрузка
tb[RTA_MAX+1] - атрибуты маршрута
*/
struct nlmsghdr *nlmp;
struct rtmsg *routemsg;
struct rtattr * tb[RTA_MAX+1];
/*
Данные в буфере имеют следующий вид:
|nlmsghdr|data|nlmsghdr|data|....|nlmsghdr|data|
|-------------------size-----------------------|
*/
for(nlmp = (struct nlmsghdr *)buffer; size > sizeof(*nlmp);){
int len;
int req_len;
/*Проверяем целостность netlink сообщения*/
if (!NLMSG_OK(nlmp, size)) {
perror("NLMSG not OK\n");
return;
}
/*Это размер сообщения netlink*/
int len = nlmp->nlmsg_len;
/*Получаем размер полезной нагрузки*/
int req_len = len - sizeof(*nlmp);
/*Проверяем тип сообщения*/
/*Если он не относится к маршрутам, то переходим на следующее сообщение*/
switch(nlmp->nlmsg_type){
case RTM_DELROUTE:
printf("A route was deleted\n");
break;
case RTM_NEWROUTE:
printf("A route was added\n");
break;
default:
size -= NLMSG_ALIGN(len);
nlmp = (struct nlmsghdr*)((char*)nlmp + NLMSG_ALIGN(len));
continue;
}
/*Получаем указатель на полезную нагрузку и , после чего, выделяем атрибуты маршрута*/
routemsg = (struct rtmsg *)NLMSG_DATA(nlmp);
/*Данная функция описана ниже.*/
parseRtattr(tb, RTA_MAX, RTM_RTA(routemsg), len);
/*Код ниже выводит атрибуты маршрута*/
if(tb[RTA_IIF]){
int iface;
iface = *(int*)RTA_DATA(tb[RTA_IIF]);
printf("An input iface is %d\n", iface);
}
if(tb[RTA_OIF]){
int iface;
iface = *(int*)RTA_DATA(tb[RTA_OIF]);
printf("An output iface is %d\n", iface);
}
if(tb[RTA_DST]){
char routeAddr[128];
inet_ntop(AF_INET6, RTA_DATA(tb[RTA_DST]), routeAddr, sizeof(routeAddr));
printf("Destination route is %s\n", routeAddr);
}else if (routemsg->rtm_dst_len) {
printf( "0/%d \n", routemsg->rtm_dst_len);
} else {
printf("Destination route is default\n");
}
if(tb[RTA_SRC]){
char routeAddr[128];
inet_ntop(AF_INET6, RTA_DATA(tb[RTA_SRC]), routeAddr, sizeof(routeAddr));
printf("Source route is %s\n", routeAddr);
}
if(tb[RTA_GATEWAY]){
char routeAddr[128];
inet_ntop(AF_INET6, RTA_DATA(tb[RTA_GATEWAY]), routeAddr, sizeof(routeAddr));
printf("Gateway is %s\n", routeAddr);
}
if(tb[RTA_PRIORITY]){
int metric ;
metric = *(int*)RTA_DATA(tb[RTA_PRIORITY]);
printf("Mertic is %d\n", metric);
}
/*Переходим на следующее сообщение*/
size -= NLMSG_ALIGN(len);
nlmp = (struct nlmsghdr*)((char*)nlmp + NLMSG_ALIGN(len));
}//for(nlmp = (struct nlmsghdr *)buffer; size > sizeof(*nlmp);){
}
Полезная нагрузка в данном случае состоит из заголовка и атрибутовмаршрута. Поэтому общий вид пакета имеет следующий вид:
Таким образом, функция для выделения атрибутов:
void parseRtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
{
memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
while(RTA_OK(rta, len)){
if(rta->rta_type <= max){
tb[rta->rta_type] = rta;
}
rta = RTA_NEXT(rta, len);
}
}
Теперь можно написать main функцию:
int main(int argc, char *argv[])
{
int nd = 0;
struct sockaddr_nl *local;
char buffer[16384];
nd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
local = malloc(sizeof(struct sockaddr_nl ));
memset(local, 0, sizeof(struct sockaddr_nl));
local->nl_family = AF_NETLINK;
/*Принимаем изменения, связанные с маршрутами ipv6*/
local->nl_groups = RTMGRP_IPV6_ROUTE;
local->nl_pid = getpid();
if(bind(nd, (struct sockaddr *)local , sizeof(struct sockaddr_nl)) < 0){
printf("Error bind\n");
return 1;
}
while(1){
/*
Эта структура непосредственно передается через сокет.
Она содержит в себе указатель на блок полезных данных,количество
данных блоков, а так же ряд дополнительных флагов и полей
*/
struct msghdr msg;
/*
Эта структура служит хранилищем полезных данных,
передаваемых через сокеты netlink. Полю iov_base присваивается указатель
на байтовый массив. Именно в этот байтовый массив будут записаны
данные сообщения.
*/
struct iovec iov;
int size = 0;
iov.iov_base = buffer;
iov.iov_len = 16000;
msg.msg_name = &local;
msg.msg_namelen = sizeof(*local);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
size = recvmsg(nd, &msg, MSG_DONTWAIT);
if(size < 0){
if(errno == EINTR || errno == EAGAIN){
usleep(250000);
continue;
}
}
show_route(buffer, size);
}
}
Комментариев нет:
Отправить комментарий