-
-
Save ripx80/ed170f5ba9ef374a5af707bfd0cfb74a to your computer and use it in GitHub Desktop.
Linux route monitoring example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
iflist.c : retrieve network interface information thru netlink sockets | |
(c) Jean Lorchat @ Internet Initiative Japan - Innovation Institute | |
v1.0 : initial version - Feb 19th 2010 | |
This file was obtained at the following address : | |
http://www.iijlab.net/~jean/iflist.c | |
Find out more on the blog post : | |
http://iijean.blogspot.com/2010/03/howto-get-list-of-network-interfaces-in.html | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/types.h> | |
#include <sys/socket.h> | |
#include <unistd.h> | |
#include <linux/netlink.h> | |
#include <linux/rtnetlink.h> | |
#define IFLIST_REPLY_BUFFER 8192 | |
/* | |
define the message structure : | |
. a netlink message | |
. a "general form of address family dependent" message, | |
i.e. how to tell which AF we are interested in | |
*/ | |
typedef struct nl_req_s nl_req_t; | |
struct nl_req_s { | |
struct nlmsghdr hdr; | |
struct rtgenmsg gen; | |
}; | |
void | |
rtnl_print_link(struct nlmsghdr *h) | |
{ | |
struct ifinfomsg *iface; | |
struct rtattr *attribute; | |
int len; | |
iface = NLMSG_DATA(h); | |
len = h->nlmsg_len - NLMSG_LENGTH(sizeof(*iface)); | |
/* loop over all attributes for the NEWLINK message */ | |
for (attribute = IFLA_RTA(iface); RTA_OK(attribute, len); attribute = RTA_NEXT(attribute, len)) | |
{ | |
switch(attribute->rta_type) | |
{ | |
case IFLA_IFNAME: | |
printf("Interface %d : %s\n", iface->ifi_index, (char *) RTA_DATA(attribute)); | |
break; | |
default: | |
break; | |
} | |
} | |
} | |
rtnl_print_route(struct nlmsghdr *nlh) | |
{ | |
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; | |
unsigned char route_netmask = 0; | |
unsigned char route_protocol = 0; | |
char destination_address[32]; | |
char gateway_address[32]; | |
printf("here we are\n"); | |
route_entry = (struct rtmsg *) NLMSG_DATA(nlh); | |
if (route_entry->rtm_table != RT_TABLE_MAIN) | |
return; | |
route_netmask = route_entry->rtm_dst_len; | |
route_protocol = route_entry->rtm_protocol; | |
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)) | |
{ | |
printf("route attribute type: %d\n", route_attribute->rta_type); | |
/* 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)); | |
} | |
} | |
printf("route to destination --> %s/%d proto %d and gateway %s\n", \ | |
destination_address, route_netmask, route_protocol, gateway_address); | |
} | |
int | |
main(int argc, char **argv) | |
{ | |
int fd; | |
struct sockaddr_nl local; /* our local (user space) side of the communication */ | |
struct sockaddr_nl kernel; /* the remote (kernel space) side of the communication */ | |
struct msghdr rtnl_msg; /* generic msghdr struct for use with sendmsg */ | |
struct iovec io; /* IO vector for sendmsg */ | |
nl_req_t req; /* structure that describes the rtnetlink packet itself */ | |
char reply[IFLIST_REPLY_BUFFER]; /* a large buffer to receive lots of link information */ | |
pid_t pid = getpid(); /* our process ID to build the correct netlink address */ | |
int end = 0; /* some flag to end loop parsing */ | |
/* | |
prepare netlink socket for kernel/userland communication | |
we are interested in the ROUTE flavor. | |
There are others like XFRM, but to deal with links, addresses and obviously routes, | |
you have to use NETLINK_ROUTE. | |
*/ | |
fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); | |
memset(&local, 0, sizeof(local)); /* fill-in local address information */ | |
local.nl_family = AF_NETLINK; | |
local.nl_pid = pid; | |
local.nl_groups = 0; | |
//local.nl_groups = RTMGRP_IPV4_ROUTE; | |
if (bind(fd, (struct sockaddr *) &local, sizeof(local)) < 0) | |
{ | |
perror("cannot bind, are you root ? if yes, check netlink/rtnetlink kernel support"); | |
return -1; | |
} | |
/* RTNL socket is ready for use, prepare and send request */ | |
memset(&rtnl_msg, 0, sizeof(rtnl_msg)); | |
memset(&kernel, 0, sizeof(kernel)); | |
memset(&req, 0, sizeof(req)); | |
kernel.nl_family = AF_NETLINK; /* fill-in kernel address (destination of our message) */ | |
kernel.nl_groups = 0; | |
req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)); | |
req.hdr.nlmsg_type = RTM_GETROUTE; | |
req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; | |
req.hdr.nlmsg_seq = 1; | |
req.hdr.nlmsg_pid = pid; | |
//req.gen.rtgen_family = AF_PACKET; /* no preferred AF, we will get *all* interfaces */ | |
req.gen.rtgen_family = AF_INET; | |
io.iov_base = &req; | |
io.iov_len = req.hdr.nlmsg_len; | |
rtnl_msg.msg_iov = &io; | |
rtnl_msg.msg_iovlen = 1; | |
rtnl_msg.msg_name = &kernel; | |
rtnl_msg.msg_namelen = sizeof(kernel); | |
sendmsg(fd, (struct msghdr *) &rtnl_msg, 0); | |
/* parse reply */ | |
while (!end) | |
{ | |
int len; | |
struct nlmsghdr *msg_ptr; /* pointer to current message part */ | |
struct msghdr rtnl_reply; /* generic msghdr structure for use with recvmsg */ | |
struct iovec io_reply; | |
memset(&io_reply, 0, sizeof(io_reply)); | |
memset(&rtnl_reply, 0, sizeof(rtnl_reply)); | |
io.iov_base = reply; | |
io.iov_len = IFLIST_REPLY_BUFFER; | |
rtnl_reply.msg_iov = &io; | |
rtnl_reply.msg_iovlen = 1; | |
rtnl_reply.msg_name = &kernel; | |
rtnl_reply.msg_namelen = sizeof(kernel); | |
len = recvmsg(fd, &rtnl_reply, 0); /* read as much data as fits in the receive buffer */ | |
if (len) | |
{ | |
for (msg_ptr = (struct nlmsghdr *) reply; NLMSG_OK(msg_ptr, len); msg_ptr = NLMSG_NEXT(msg_ptr, len)) | |
{ | |
switch(msg_ptr->nlmsg_type) | |
{ | |
case 3: /* this is the special meaning NLMSG_DONE message we asked for by using NLM_F_DUMP flag */ | |
end++; | |
break; | |
case 16: /* this is a RTM_NEWLINK message, which contains lots of information about a link */ | |
rtnl_print_link(msg_ptr); | |
break; | |
case 24: | |
rtnl_print_route(msg_ptr); | |
break; | |
default: /* for education only, print any message that would not be DONE or NEWLINK, | |
which should not happen here */ | |
printf("message type %d, length %d\n", msg_ptr->nlmsg_type, msg_ptr->nlmsg_len); | |
break; | |
} | |
} | |
} | |
} | |
/* clean up and finish properly */ | |
close(fd); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* The purpose of this program is to monitor routing | |
* table changes | |
*/ | |
#include <sys/socket.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <linux/netlink.h> | |
#include <linux/rtnetlink.h> | |
#include <arpa/inet.h> | |
#include <unistd.h> | |
#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]; | |
unsigned char route_netmask = 0; | |
unsigned char route_protocol = 0; | |
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; | |
*/ | |
/* | |
if (route_entry->rtm_protocol != RTPROT_UNSPEC) | |
continue; | |
*/ | |
route_netmask = route_entry->rtm_dst_len; | |
route_protocol = route_entry->rtm_protocol; | |
/* 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/%d proto %d and gateway %s\n", \ | |
destination_address, route_netmask, route_protocol, gateway_address); | |
if (nlh->nlmsg_type == RTM_NEWROUTE) | |
printf("Adding route to destination --> %s/%d proto %d and gateway %s\n", \ | |
destination_address, route_netmask, route_protocol, 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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment