Skip to content

Instantly share code, notes, and snippets.

@jshen28
Forked from cl4u2/route_dump.c
Created June 7, 2020 10:11
Show Gist options
  • Save jshen28/8b36be1cb1ae0e45954d3797d9b97c3a to your computer and use it in GitHub Desktop.
Save jshen28/8b36be1cb1ae0e45954d3797d9b97c3a to your computer and use it in GitHub Desktop.

Revisions

  1. @cl4u2 cl4u2 created this gist Mar 20, 2013.
    229 changes: 229 additions & 0 deletions route_dump.c
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,229 @@
    /*
    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;
    }
    138 changes: 138 additions & 0 deletions route_monitor.c
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,138 @@
    /* 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;
    }