美文网首页
Linux libnl 编程

Linux libnl 编程

作者: louyang | 来源:发表于2017-11-29 20:40 被阅读403次

    libnl 是用来简化 Netlink 编程的。

    例子 1

    使用 libnl 提供的 API 列出当前 Linux 系统中的所有网卡。

    /*
     *  List all network interfaces
     */
    #include <stdio.h>   //printf, perror
    #include <stdlib.h>  //exit
    #include <netlink/netlink.h>
    #include <netlink/genl/genl.h>
    
    static int print_link(struct nl_msg * msg, void * arg)
    {
        struct nlmsghdr * h = nlmsg_hdr(msg);
        struct ifinfomsg * iface = NLMSG_DATA(h);
        struct rtattr * attr = IFLA_RTA(iface);
        int remaining = RTM_PAYLOAD(h);
    
        for (; RTA_OK(attr, remaining); attr = RTA_NEXT(attr, remaining))
        {
            switch (attr->rta_type)
            {
            case IFLA_IFNAME:
                printf("Interface %d : %s\n", iface->ifi_index, (char *)RTA_DATA(attr));
                break;
            default:
                break;
            }
        }
    
        return NL_OK;
    }
    
    void die(char * s)
    {
        perror(s);
        exit(1);
    }
    
    int main(void)
    {
        struct nl_sock * s = nl_socket_alloc();
        if (s == NULL) {
            die("nl_socket_alloc");
        }
    
        if (nl_connect(s, NETLINK_ROUTE) < 0) {
            nl_socket_free(s);
            die("nl_connet");
        }
    
        struct rtgenmsg rt_hdr = { .rtgen_family = AF_NETLINK, };
        if (nl_send_simple(s, RTM_GETLINK, NLM_F_REQUEST|NLM_F_DUMP, &rt_hdr, sizeof(rt_hdr)) < 0) {
            nl_socket_free(s);
            die("nl_send_simple");
        }
    
        //Retrieve the kernel's answer.
        nl_socket_modify_cb(s, NL_CB_VALID, NL_CB_CUSTOM, print_link, NULL);
        nl_recvmsgs_default(s);
    
        nl_socket_free(s);
        return 0;
    }
    
    # gcc link-list.c -o link-list $(pkg-config --cflags --libs libnl-genl-3.0) && ./link-list
    Interface 1 : lo
    Interface 2 : eth0
    
    例子 2

    使用 libnl 提供的 API 列出当前 Linux 系统中的所有 IP 地址。

    /*
     *  List all IP addresses
     */
    #include <stdio.h>   //printf, perror
    #include <stdlib.h>  //exit
    #include <netlink/netlink.h>
    #include <netlink/genl/genl.h>
    
    static int print_addr(struct nl_msg * msg, void * arg)
    {
        struct nlmsghdr * h = nlmsg_hdr(msg);
        struct ifaddrmsg * addr = NLMSG_DATA(h);
        struct rtattr * attr = IFLA_RTA(addr);
        int remaining = RTM_PAYLOAD(h);
    
        for (; RTA_OK(attr, remaining); attr = RTA_NEXT(attr, remaining))
        {
            switch (attr->rta_type)
            {
            case IFA_LABEL:
                printf("Interface  : %s\n", (char *)RTA_DATA(attr));
                break;
            case IFA_LOCAL:
            {
                int ip = *(int*)RTA_DATA(attr);
                unsigned char bytes[4];
                bytes[0] = ip & 0xFF;
                bytes[1] = (ip >> 8) & 0xFF;
                bytes[2] = (ip >> 16) & 0xFF;
                bytes[3] = (ip >> 24) & 0xFF;
                printf("IP Address : %d.%d.%d.%d\n", bytes[0], bytes[1], bytes[2], bytes[3]);
                break;
            }
            default:
                break;
            }
        }
    
        return NL_OK;
    }
    
    void die(char * s)
    {
        perror(s);
        exit(1);
    }
    
    int main(void)
    {
        struct nl_sock * s = nl_socket_alloc();
        if (s == NULL) {
            die("nl_socket_alloc");
        }
    
        if (nl_connect(s, NETLINK_ROUTE) < 0) {
            nl_socket_free(s);
            die("nl_connet");
        }
    
        struct rtgenmsg rt_hdr = { .rtgen_family = AF_NETLINK, };
        if (nl_send_simple(s, RTM_GETADDR, NLM_F_REQUEST|NLM_F_DUMP, &rt_hdr, sizeof(rt_hdr)) < 0) {
            nl_socket_free(s);
            die("nl_send_simple");
        }
    
        //Retrieve the kernel's answer.
        nl_socket_modify_cb(s, NL_CB_VALID, NL_CB_CUSTOM, print_addr, NULL);
        nl_recvmsgs_default(s);
    
        nl_socket_free(s);
        return 0;
    }
    
    # gcc addr-list.c -o addr-list $(pkg-config --cflags --libs libnl-genl-3.0) && ./addr-list
    IP Address : 127.0.0.1
    Interface  : lo
    IP Address : 10.254.108.206
    Interface  : eth0
    
    例子 3

    使用 libnl 提供的 API 列出当前 Linux 系统中主路由表中的所有路由。

    /*
     *  List all routes in main route table
     */
    #include <stdio.h>     //printf, perror
    #include <stdlib.h>    //exit
    #include <arpa/inet.h> //inet_ntop
    #include <netlink/netlink.h>
    #include <netlink/genl/genl.h>
    
    static int print_route(struct nl_msg * msg, void * arg)
    {
        struct nlmsghdr * h = nlmsg_hdr(msg);
        struct rtmsg * rte = NLMSG_DATA(h);
        struct rtattr * attr = RTM_RTA(rte);
        int remaining = RTM_PAYLOAD(h);
        char dest[64] = {0};
        char gway[64] = {"unspecified"};
    
        if (rte->rtm_table != RT_TABLE_MAIN) {
            return NL_OK;
        }
    
        for (; RTA_OK(attr, remaining); attr = RTA_NEXT(attr, remaining))
        {
            switch (attr->rta_type)
            {
            case RTA_DST:
                if (rte->rtm_dst_len < 32)
                    inet_ntop(AF_INET, RTA_DATA(attr), dest, sizeof(dest));
                else
                    inet_ntop(AF_INET6, RTA_DATA(attr), dest, sizeof(dest));
                break;
            case RTA_GATEWAY:
                if (rte->rtm_dst_len < 32)
                    inet_ntop(AF_INET, RTA_DATA(attr), gway, sizeof(gway));
                else
                    inet_ntop(AF_INET6, RTA_DATA(attr), gway, sizeof(gway));
                break;
            default:
                break;
            }
        }
    
        printf("%s/%d gateway %s\n", dest, rte->rtm_dst_len, gway);
        return NL_OK;
    }
    
    void die(char * s)
    {
        perror(s);
        exit(1);
    }
    
    int main(void)
    {
        struct nl_sock * s = nl_socket_alloc();
        if (s == NULL) {
            die("nl_socket_alloc");
        }
    
        if (nl_connect(s, NETLINK_ROUTE) < 0) {
            nl_socket_free(s);
            die("nl_connet");
        }
    
        struct rtgenmsg rt_hdr = { .rtgen_family = AF_NETLINK, };
        if (nl_send_simple(s, RTM_GETROUTE, NLM_F_REQUEST|NLM_F_DUMP, &rt_hdr, sizeof(rt_hdr)) < 0) {
            nl_socket_free(s);
            die("nl_send_simple");
        }
    
        //Retrieve the kernel's answer.
        nl_socket_modify_cb(s, NL_CB_VALID, NL_CB_CUSTOM, print_route, NULL);
        nl_recvmsgs_default(s);
    
        nl_socket_free(s);
        return 0;
    }
    
    # gcc route-list.c -o route-list $(pkg-config --cflags --libs libnl-genl-3.0) && ./route-list
    /0 gateway 10.254.96.136
    10.254.96.0/19 gateway unspecified
    fe80::/64 gateway unspecified
    
    例子 4

    使用 libnl 提供的 API,检测当前 Linux 系统中主路由表中的路由变化。

    /*
     *  Monitor route change
     */
    #include <stdio.h>     //printf, perror
    #include <stdlib.h>    //exit
    #include <arpa/inet.h> //inet_ntop
    #include <netlink/netlink.h>
    #include <netlink/genl/genl.h>
    
    static int print_route(struct nl_msg * msg, void * arg)
    {
        struct nlmsghdr * h = nlmsg_hdr(msg);
        struct rtmsg * rte = NLMSG_DATA(h);
        struct rtattr * attr = RTM_RTA(rte);
        int remaining = RTM_PAYLOAD(h);
        char dest[64] = {0};
        char gway[64] = {"unspecified"};
    
        if (rte->rtm_table != RT_TABLE_MAIN) {
            return NL_OK;
        }
    
        for (; RTA_OK(attr, remaining); attr = RTA_NEXT(attr, remaining))
        {
            switch (attr->rta_type)
            {
            case RTA_DST:
                if (rte->rtm_dst_len < 32)
                    inet_ntop(AF_INET, RTA_DATA(attr), dest, sizeof(dest));
                else
                    inet_ntop(AF_INET6, RTA_DATA(attr), dest, sizeof(dest));
                break;
            case RTA_GATEWAY:
                if (rte->rtm_dst_len < 32)
                    inet_ntop(AF_INET, RTA_DATA(attr), gway, sizeof(gway));
                else
                    inet_ntop(AF_INET6, RTA_DATA(attr), gway, sizeof(gway));
                break;
            default:
                break;
            }
        }
    
        if (h->nlmsg_type == RTM_NEWROUTE) {
            printf("add ");
        }
        else if (h->nlmsg_type == RTM_DELROUTE) {
            printf("del ");
        }
        else {
            printf("nlmsg_type=%d ", h->nlmsg_type);
        }
        printf("%s/%d gateway %s\n", dest, rte->rtm_dst_len, gway);
        return NL_OK;
    }
    
    void die(char * s)
    {
        perror(s);
        exit(1);
    }
    
    int main(void)
    {
        struct nl_sock * s = nl_socket_alloc();
        if (s == NULL) {
            die("nl_socket_alloc");
        }
    
        nl_socket_disable_seq_check(s);
        nl_socket_modify_cb(s, NL_CB_VALID, NL_CB_CUSTOM, print_route, NULL);
    
        if (nl_connect(s, NETLINK_ROUTE) < 0) {
            nl_socket_free(s);
            die("nl_connet");
        }
    
        nl_socket_add_memberships(s, RTNLGRP_IPV4_ROUTE, 0);
    
        while(1)
        {
            nl_recvmsgs_default(s);
        }
    
        nl_socket_free(s);
        return 0;
    }
    
    Terminal 1:
    # gcc route-chg.c -o route-chg $(pkg-config --cflags --libs libnl-genl-3.0) && ./route-chg
    
    Terminal 2:
    # ip route add 199.1.1.0/24 via 10.254.96.150
    # ip route del 199.1.1.0/24 via 10.254.96.150
    
    Terminal 1:
    # gcc route-chg.c -o route-chg $(pkg-config --cflags --libs libnl-genl-3.0) && ./route-chg
    add 199.1.1.0/24 gateway 10.254.96.150
    del 199.1.1.0/24 gateway 10.254.96.150
    
    参考文献

    1 https://www.infradead.org/~tgr/libnl/doc/core.html
    2 https://github.com/Robpol86/libnl/blob/master/example_c/list_network_interfaces.c

    相关文章

      网友评论

          本文标题:Linux libnl 编程

          本文链接:https://www.haomeiwen.com/subject/xoypbxtx.html