Linux libnl 編程

libnl 是用來簡化 Netlink 編程的。

例子 1

使用 libnl 提供的 API 列出當(dāng)前 Linux 系統(tǒng)中的所有網(wǎng)卡湃密。

/*
 *  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 列出當(dāng)前 Linux 系統(tǒng)中的所有 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 列出當(dāng)前 Linux 系統(tǒng)中主路由表中的所有路由蛾坯。

/*
 *  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,檢測當(dāng)前 Linux 系統(tǒng)中主路由表中的路由變化疏遏。

/*
 *  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
參考文獻(xiàn)

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末脉课,一起剝皮案震驚了整個(gè)濱河市救军,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌倘零,老刑警劉巖唱遭,帶你破解...
    沈念sama閱讀 223,126評論 6 520
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異呈驶,居然都是意外死亡拷泽,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,421評論 3 400
  • 文/潘曉璐 我一進(jìn)店門袖瞻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來司致,“玉大人,你說我怎么就攤上這事聋迎≈茫” “怎么了?”我有些...
    開封第一講書人閱讀 169,941評論 0 366
  • 文/不壞的土叔 我叫張陵霉晕,是天一觀的道長庭再。 經(jīng)常有香客問我,道長牺堰,這世上最難降的妖魔是什么拄轻? 我笑而不...
    開封第一講書人閱讀 60,294評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮伟葫,結(jié)果婚禮上恨搓,老公的妹妹穿的比我還像新娘。我一直安慰自己筏养,他們只是感情好奶卓,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,295評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著撼玄,像睡著了一般。 火紅的嫁衣襯著肌膚如雪墩邀。 梳的紋絲不亂的頭發(fā)上掌猛,一...
    開封第一講書人閱讀 52,874評論 1 314
  • 那天,我揣著相機(jī)與錄音眉睹,去河邊找鬼荔茬。 笑死,一個(gè)胖子當(dāng)著我的面吹牛竹海,可吹牛的內(nèi)容都是我干的慕蔚。 我是一名探鬼主播,決...
    沈念sama閱讀 41,285評論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼斋配,長吁一口氣:“原來是場噩夢啊……” “哼孔飒!你這毒婦竟也來了灌闺?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,249評論 0 277
  • 序言:老撾萬榮一對情侶失蹤坏瞄,失蹤者是張志新(化名)和其女友劉穎桂对,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鸠匀,經(jīng)...
    沈念sama閱讀 46,760評論 1 321
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蕉斜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,840評論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了缀棍。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宅此。...
    茶點(diǎn)故事閱讀 40,973評論 1 354
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖爬范,靈堂內(nèi)的尸體忽然破棺而出父腕,到底是詐尸還是另有隱情,我是刑警寧澤坦敌,帶...
    沈念sama閱讀 36,631評論 5 351
  • 正文 年R本政府宣布侣诵,位于F島的核電站,受9級特大地震影響狱窘,放射性物質(zhì)發(fā)生泄漏杜顺。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,315評論 3 336
  • 文/蒙蒙 一蘸炸、第九天 我趴在偏房一處隱蔽的房頂上張望躬络。 院中可真熱鬧,春花似錦搭儒、人聲如沸穷当。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,797評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽馁菜。三九已至,卻和暖如春铃岔,著一層夾襖步出監(jiān)牢的瞬間汪疮,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,926評論 1 275
  • 我被黑心中介騙來泰國打工毁习, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留智嚷,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,431評論 3 379
  • 正文 我出身青樓纺且,卻偏偏與公主長得像盏道,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子载碌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,982評論 2 361

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理猜嘱,服務(wù)發(fā)現(xiàn)衅枫,斷路器,智...
    卡卡羅2017閱讀 134,720評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,348評論 25 707
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,871評論 6 342
  • 其實(shí)泉坐,你是我第一個(gè)喜歡的人为鳄,但是現(xiàn)在我卻給不了你最初的單純,因?yàn)樽詈玫囊呀?jīng)給了別人腕让,第一次接吻孤钦,第一次牽手,第一...
    黑暗小蘿莉閱讀 256評論 0 0
  • 如題俊扭,我今晚約飯了秋葉大叔和剽悍一只貓,還有沈小怡坠陈,王歐飏萨惑,Lena 。后面三位是秋葉大叔IP訓(xùn)練營群員和準(zhǔn)群員仇矾,...
    鄭喜月閱讀 489評論 4 9