从netlink消息中提取当前路由,附加代码

我正在尝试使用netlink套接字监视路由更改,但是如何获取更新的路由地址?

码:

#include  #include  #include  #include  #include  #include  #define ERR_RET(x) do { perror(x); return EXIT_FAILURE; } while (0); void loop (int sock) { struct sockaddr_nl nladdr; struct msghdr msg; struct iovec iov[2]; struct nlmsghdr nlh; char buffer[65536]; iov[0].iov_base = (void *)&nlh; iov[0].iov_len = sizeof(nlh); iov[1].iov_base = (void *)buffer; iov[1].iov_len = sizeof(buffer); msg.msg_name = (void *)&(nladdr); msg.msg_namelen = sizeof(nladdr); msg.msg_iov = iov; msg.msg_iovlen = sizeof(iov)/sizeof(struct iovec); if ( recvmsg (sock, &msg, 0) ) { if ( nlh.nlmsg_type == RTM_NEWROUTE ) { printf ("New route message\n"); } else if ( nlh.nlmsg_type == RTM_DELROUTE ) { printf ("Del route message\n"); } } } int main(int argc, char *argv[]) { int sock = -1; struct sockaddr_nl addr; bzero (&addr, sizeof(addr)); if ( (sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE) ) < 0 ) ERR_RET("socket"); addr.nl_family = AF_NETLINK; addr.nl_groups = RTMGRP_IPV4_ROUTE; if (bind(sock,(struct sockaddr *)&addr,sizeof(addr))<0) ERR_RET("bind"); while (1) loop (sock); return 0; } 

我编辑了你的代码并添加了两个结构(),以便在路由表更改时获得所需的信息(代码被注释)。

 /* The purpose of this program is to monitor routing table changes */ #include  #include  #include  #include  #include  #include  #include  #include  #define ERR_RET(x) do { perror(x); return EXIT_FAILURE; } while (0); #define BUFFER_SIZE 4095 int loop (int sock, struct sockaddr_nl *addr) { int received_bytes = 0; struct nlmsghdr *nlh; char destination_address[32]; char gateway_address[32]; struct rtmsg *route_entry; /* This struct represent a route entry \ in the routing table */ struct rtattr *route_attribute; /* This struct contain route \ attributes (route type) */ int route_attribute_len = 0; char buffer[BUFFER_SIZE]; bzero(destination_address, sizeof(destination_address)); bzero(gateway_address, sizeof(gateway_address)); bzero(buffer, sizeof(buffer)); /* Receiving netlink socket data */ while (1) { received_bytes = recv(sock, buffer, sizeof(buffer), 0); if (received_bytes < 0) ERR_RET("recv"); /* cast the received buffer */ nlh = (struct nlmsghdr *) buffer; /* If we received all data ---> break */ if (nlh->nlmsg_type == NLMSG_DONE) break; /* We are just intrested in Routing information */ if (addr->nl_groups == RTMGRP_IPV4_ROUTE) break; } /* Reading netlink socket data */ /* Loop through all entries */ /* For more informations on some functions : * http://www.kernel.org/doc/man-pages/online/pages/man3/netlink.3.html * http://www.kernel.org/doc/man-pages/online/pages/man7/rtnetlink.7.html */ for ( ; NLMSG_OK(nlh, received_bytes); \ nlh = NLMSG_NEXT(nlh, received_bytes)) { /* Get the route data */ route_entry = (struct rtmsg *) NLMSG_DATA(nlh); /* We are just intrested in main routing table */ if (route_entry->rtm_table != RT_TABLE_MAIN) continue; /* Get attributes of route_entry */ route_attribute = (struct rtattr *) RTM_RTA(route_entry); /* Get the route atttibutes len */ route_attribute_len = RTM_PAYLOAD(nlh); /* Loop through all attributes */ for ( ; RTA_OK(route_attribute, route_attribute_len); \ route_attribute = RTA_NEXT(route_attribute, route_attribute_len)) { /* Get the destination address */ if (route_attribute->rta_type == RTA_DST) { inet_ntop(AF_INET, RTA_DATA(route_attribute), \ destination_address, sizeof(destination_address)); } /* Get the gateway (Next hop) */ if (route_attribute->rta_type == RTA_GATEWAY) { inet_ntop(AF_INET, RTA_DATA(route_attribute), \ gateway_address, sizeof(gateway_address)); } } /* Now we can dump the routing attributes */ if (nlh->nlmsg_type == RTM_DELROUTE) fprintf(stdout, "Deleting route to destination --> %s and gateway %s\n", \ destination_address, gateway_address); if (nlh->nlmsg_type == RTM_NEWROUTE) printf("Adding route to destination --> %s and gateway %s\n", \ destination_address, gateway_address); } return 0; } int main(int argc, char **argv) { int sock = -1; struct sockaddr_nl addr; /* Zeroing addr */ bzero (&addr, sizeof(addr)); if ((sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) ERR_RET("socket"); addr.nl_family = AF_NETLINK; addr.nl_groups = RTMGRP_IPV4_ROUTE; if (bind(sock,(struct sockaddr *)&addr,sizeof(addr)) < 0) ERR_RET("bind"); while (1) loop (sock, &addr); /* Close socket */ close(sock); return 0; } 

您可以像这样测试(以root身份添加路由到路由表):

 root@UnixServer# route add -host 10.113.0.0 gw bsdBox root@UnixServer# route del -host 10.113.0.0 gw bsdBox 

在我的机器上我得到了这个输出:

 toc@UnixServer:~$./route_monitor Adding route to destination --> 10.113.0.0 and gateway 192.168.1.1 Deleting route to destination --> 10.113.0.0 and gateway 192.168.1.1 ^C