LINUX.ORG.RU

rtnetlink уведомить пользователя

 , ,


0

2

Привет всем. Используя rtnetlink, получаю адрес шлюза. В man 7 rtnetlink есть опция в rtm_flags с названием RTM_F_NOTIFY. описание (if the route changes, notify the user via rtnetlink) (если маршрут измениться, уведомить пользователя через rtnetlink)

Но у меня не происходит уведомления, не приходит новых сообщений, что не так?

#include <stdio.h>
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/if_link.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <strings.h>
#include <string.h>
#include <arpa/inet.h>

struct 
{
	struct nlmsghdr nh;
	struct rtmsg rtmsg;
	char buf[8192];
}req;

int main(int argc, char *argv[])
{
	int rtnetlink_socket;

	if((rtnetlink_socket = socket(AF_NETLINK,SOCK_DGRAM,NETLINK_ROUTE)) == -1)
	{
		perror("socket");
		exit(-1);
	}


	memset(&req,0,sizeof(req));

	req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
	req.nh.nlmsg_type = RTM_GETROUTE;
	req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;

	req.rtmsg.rtm_family = AF_INET;
	req.rtmsg.rtm_table = 0;
	req.rtmsg.rtm_type = RTN_UNICAST;
	req.rtmsg.rtm_protocol = RTPROT_STATIC;
	req.rtmsg.rtm_scope = RT_SCOPE_LINK;
	req.rtmsg.rtm_flags = RTM_F_NOTIFY;
	req.rtmsg.rtm_table = RT_TABLE_MAIN;

	unsigned int intaddr = 0;
	struct rtattr *rta;
	rta = (struct rtattr *)(((char *) &req) + NLMSG_ALIGN(req.nh.nlmsg_len));	
	rta->rta_type =  RTA_GATEWAY;
	rta->rta_len = RTA_LENGTH(sizeof(unsigned int));
	req.nh.nlmsg_len = NLMSG_ALIGN(req.nh.nlmsg_len) + RTA_LENGTH(sizeof(intaddr));

	memcpy(RTA_DATA(rta), &intaddr, sizeof(intaddr));

	if(send(rtnetlink_socket,&req,req.nh.nlmsg_len,0) == -1)
	{
		perror("send");
		close(rtnetlink_socket);
		exit(-1);
	}

	int recvlen = 0;
	int counter = 8192;
	char buffer[counter];

	struct nlmsghdr *nl;
	int replylen = 0;
	int i = 0;
	for(;;)
	{
		recvlen = recv(rtnetlink_socket,&buffer,1500,0);
		printf("recvlen = %d\n",recvlen);
		if(recvlen < 0)
		{
			printf("recvlen < 0\n");
			break;
		}

		if(recvlen == 0)
			printf("eof in netlink\n");

		int nll;
		struct rtmsg *rtp;
		nl = (struct nlmsghdr *)&buffer[replylen];
		rtp = (struct rtmsg *) NLMSG_DATA(nl);

		if(rtp->rtm_table != RT_TABLE_MAIN)
		{
			printf("non table main %d\n",rtp->rtm_table);
			continue;
		}
		char gws[24];
		struct rtattr *rtap;
		rtap = (struct rtattr *) RTM_RTA(rtp);
		int rtl = 0;
		rtl = RTM_PAYLOAD(nl);
		for(; RTA_OK(rtap,rtl);rtap=RTA_NEXT(rtap,rtl))
		{
			switch(rtap->rta_type)
			{
				case RTA_GATEWAY:
					inet_ntop(AF_INET, RTA_DATA(rtap),gws,24);
					printf("%s\n",gws);
			//		return 0;
					break;
			}
		}
	
		if(nl->nlmsg_type == NLMSG_DONE)
		{
			printf("nlmsg done\n");
			break;
		}

		if(nl->nlmsg_type == NLMSG_ERROR)
		{
			printf("error in nl\n");
			exit(-1);
		}
		if(nl->nlmsg_type == NLMSG_NOOP)
		{
			printf("nothing.\n");
			exit(-1);
		}
		if(nl->nlmsg_type == NLMSG_OVERRUN)
		{
			printf("data lost\n");
			exit(-1);
		}
		if(nl->nlmsg_type == NLMSG_MIN_TYPE)
		{
			printf("reserved control message\n");
			exit(-1);
		}
		replylen += recvlen;
		counter -= recvlen;

	}
		close(rtnetlink_socket);
}

Bind не вижу

anonymous ()
Ответ на: комментарий от anonymous

вот, он может быть после сокета

  struct sockaddr_nl la;
  bzero(&la,sizeof(la));
  la.nl_family = AF_NETLINK;
  la.nl_pad = 0;
  la.nl_pid = getpid();
  la.nl_groups = 0;
  if(bind(rtnetlink_socket, (struct sockaddr*) &la, sizeof(la))==-1)
  {
    perror("bind");
    close(rtnetlink_socket);
    exit(-1);
  }

u0atgKIRznY5 ()

Только сообщение о смене маршрута всё равно не приходит.

u0atgKIRznY5 ()
Ответ на: комментарий от u0atgKIRznY5

А bind к правильному порту сделан?

gag ★★★★★ ()
Ответ на: комментарий от gag
struct sockaddr_nl {
  __kernel_sa_family_t  nl_family;  /* AF_NETLINK */
  unsigned short  nl_pad;   /* zero   */
  __u32   nl_pid;   /* port ID  */
        __u32   nl_groups;  /* multicast groups mask */
};

А какой нужно порт и где это вычитать?

u0atgKIRznY5 ()
Ответ на: комментарий от u0atgKIRznY5
  __u32   nl_pid;   /* port ID  */

Случай, когда pid != pid.

  la.nl_pid = getpid();

Но, похоже, нужен просто уникальный номер, так что сойдёт.

gag ★★★★★ ()

И что же делать то, при смене сети, происходит смена маршрута, а программе оповещение не отправляется.

u0atgKIRznY5 ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.