Linux libnl 编程

libnl 是用来简化 Netlink 编程的。

例子 1

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

/*
 *  List all network interfaces
 */
#include    //printf, perror
#include   //exit
#include 
#include 

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    //printf, perror
#include   //exit
#include 
#include 

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      //printf, perror
#include     //exit
#include  //inet_ntop
#include 
#include 

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      //printf, perror
#include     //exit
#include  //inet_ntop
#include 
#include 

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 编程)