DDNS 的工作原理及其在 Linux 上的實(shí)現(xiàn)
DDNS 工作原理的分析
DDNS 的實(shí)現(xiàn)最根本的一點(diǎn)是當(dāng)主機(jī)的 IP 地址發(fā)生變化的時(shí)候,實(shí)現(xiàn) DNS 映射信息的及時(shí)更新,應(yīng)用程序需要及時(shí)地獲得這一信息,主要的方法可分為兩大類:
一類是輪詢機(jī)制,即:應(yīng)用程序每隔一定的時(shí)間,去從查詢主機(jī)當(dāng)前的 IP 地址,并與之前的進(jìn)行比較,從而判斷網(wǎng)絡(luò)地址是否發(fā)生了變化。顯然,這種方法不僅效率低下,而且對(duì)每次查詢 IP 地址的時(shí)間間隔很難得到一個(gè)折中的數(shù)值。
第二類方法是異步實(shí)現(xiàn)方式,即:每當(dāng)主機(jī)的 IP 地址發(fā)生變化的時(shí)候,應(yīng)用程序能夠被及時(shí)地通知到。這的確是一個(gè)簡(jiǎn)單而又高效的方法,但與此同時(shí),另一個(gè)問題又產(chǎn)生了,那就是:通知源又應(yīng)該由誰來擔(dān)當(dāng)呢?顯然,這是處于用戶空間的應(yīng)用程序無法勝任的。于是,我們想到了讓內(nèi)核來充當(dāng)這一消息源。這樣,在內(nèi)核空間和用戶空間之間就需要通過消息來進(jìn)行通信了。
在 Linux 下用戶空間與內(nèi)核空間的信息交互方式有許多種,比如:軟中斷、系統(tǒng)調(diào)用、netlink 等等。關(guān)于這些通信方式的介紹以及其各自的優(yōu)缺點(diǎn)并不在本文的討論范圍內(nèi),您可以自行查看參考資源。
在這許多種通信方式中,netlink 憑借其標(biāo)準(zhǔn)的 socket API、模塊化實(shí)現(xiàn)、異步通信機(jī)制、多播機(jī)制等等多種優(yōu)勢(shì),成為了內(nèi)核與越來越多應(yīng)用程序之間交互的主要方式。在 Linux 的內(nèi)核中,已經(jīng)為我們封裝了使用 netlink 對(duì)特定網(wǎng)絡(luò)狀態(tài)變化進(jìn)行消息通知的功能,這就是著名的 rtnetlink。有關(guān) netlink 在內(nèi)核空間實(shí)現(xiàn)的詳細(xì)代碼以及其 API 參數(shù)的介紹,您可以自行查看參考資源,本文在此不作過多的贅述。
本文討論的重點(diǎn)是針對(duì) DDNS 這一特定的應(yīng)用,演示 rtnetlink 檢測(cè)到 IP 地址發(fā)生了變化、并將消息告知用戶空間的應(yīng)用程序的整個(gè)過程,以及應(yīng)用程序利用 netlink 套接字接收消息、并告知 DNS 服務(wù)器的實(shí)現(xiàn)方法。
DDNS 工作流程的簡(jiǎn)單介紹
結(jié)合上述對(duì) DDNS 工作原理的分析,我們可以將 DDNS 的工作流程簡(jiǎn)單地用圖 1 來表示:
圖 1. DDNS 的工作流程圖
從圖 1 中可以看到,DDNS 的工作流程主要有三個(gè)部分:
應(yīng)用程序?qū)崟r(shí)感知到 IP 地址發(fā)生了變化,如上介紹,利用基于 netlink 的異步通知機(jī)制可以讓應(yīng)用程序及時(shí)得到內(nèi)核空間對(duì)這些事件的“通知”,具體可以分為如下 5 個(gè)步驟:
1、內(nèi)核空間初始化 rtnetlink 模塊,創(chuàng)建 NETLINK_ROUTE 協(xié)議簇類型的 netlink 套接字;
2、用戶空間創(chuàng)建 NETLINK_ROUTE 協(xié)議簇類型的 netlink 套接字,并且綁定到 RTMGRP_IPV4_IFADDR 組播 group 中;
3、用戶空間接收從內(nèi)核空間發(fā)來的消息,如果沒有消息,則阻塞自身;
4、當(dāng)主機(jī)被分配了新的 IPV4 地址,內(nèi)核空間通過 netlink_broadcast,將 RTM_NEWADDR 消息發(fā)送到 RTNLGRP_IPV4_IFADDR 組播 group 中 ;
5、用戶空間接收消息,進(jìn)行驗(yàn)證、處理;
應(yīng)用程序接收到“通知”后,把 DNS update 信息發(fā)送給 DNS 服務(wù)器,目的是將更新后的 IP 地址及時(shí)地通知 DNS 服務(wù)器,以便網(wǎng)絡(luò)上的主機(jī)仍然能夠通過原來的域名訪問到自己,通用的做法是利用開源軟件 nsupdate 發(fā)送 DNS update 信息給 DNS 服務(wù)器以實(shí)現(xiàn) DNS 信息的動(dòng)態(tài)更新。
最后,對(duì)應(yīng)于第一部分 netlink 套接字的創(chuàng)建,用戶空間和內(nèi)核空間關(guān)閉所創(chuàng)建的 netlink 套接字。
下文將詳細(xì)闡述其中的每一環(huán)節(jié)及其實(shí)現(xiàn)。
內(nèi)核空間 rtnetlink 檢測(cè) IP 地址變化的實(shí)現(xiàn)與分析
在我們開始利用 netlink 套接字、實(shí)現(xiàn)與內(nèi)核通信的應(yīng)用程序之前,先來分析一下內(nèi)核空間的 rtnetlink 模塊是如何工作的。
內(nèi)核空間 rtnetlink 的初始化
清單 1. rtnetlink 的初始化
/* 以下代碼摘自 Linux kernel 2.6.18, net/core/rtnetlink.c 文件, 并只選擇了與本主題相關(guān)的最重要的部分,其他的都用省略號(hào)略過,之后的各清單也一樣。 */ void __init rtnetlink_init(void) { ...... rtnl = netlink_kernel_create(NETLINK_ROUTE, RTNLGRP_MAX, rtnetlink_rcv, THIS_MODULE); if (rtnl == NULL) panic("rtnetlink_init: cannot initialize rtnetlink\n"); ...... }
從清單 1 中可以看到:
在 rtnetlink 進(jìn)行初始化的時(shí)候,首先會(huì)調(diào)用 netlink_kernel_create 來創(chuàng)建一個(gè) NETLINK_ROUTE 類型的 netlink 套接字,并指定接收函數(shù)為 rtnetlink_rcv,有關(guān) rtnetlink_rcv 的實(shí)現(xiàn)細(xì)節(jié)可以查閱內(nèi)核 net/core/rtnetlink.c 文件。這里需要指出的是,netlink 提供了包括 NETLINK_ROUTE、NETLINK_FIREWALL、NETLINK_INET_DIAG 等在內(nèi)的多種協(xié)議簇(詳細(xì)列表及各協(xié)議簇的含義可以自行查看參考資源),其中 NETLINK_ROUTE 類型提供了網(wǎng)絡(luò)地址發(fā)生變化的消息,這正是 DDNS 需要用到的。
內(nèi)核空間 IP 地址變化事件的通知過程
引起主機(jī) IP 地址變化的原因有很多種,如:DHCP 分配的 IP 過期、用戶手動(dòng)修改了 IP 等等。無論何種原因,最終都會(huì)觸發(fā)內(nèi)核空間對(duì)相應(yīng)事件的通知機(jī)制,這里以最常用的修改 IPV4 地址的工具 ifconfig 為例。
ifconfig 先是創(chuàng)建一個(gè) AF_INET 的 socket,然后通過系統(tǒng)調(diào)用 ioctl 來完成配置的,ioctl 在內(nèi)核中對(duì)應(yīng)的函數(shù)是 sys_ioctl,對(duì)于 IP 地址、子網(wǎng)掩碼、默認(rèn)網(wǎng)關(guān)等配置的修改,其最終會(huì)調(diào)用 devinet_ioctl。devinet_ioctl 函數(shù)處理包括 get、set 在內(nèi)的多種命令,與 DDNS 應(yīng)用有關(guān)的是 set 類命令,圖 2 給出了 SIOCSIFADDR 命令(設(shè)置網(wǎng)絡(luò)地址)的 ifconfig 調(diào)用樹:
圖 2. SIOCSIFADDR 命令的 ifconfig 調(diào)用樹
從圖 2 中可以看到,當(dāng)用戶使用 ifconfig 對(duì)主機(jī)的 IP 地址作了修改,內(nèi)核在進(jìn)行了新地址的設(shè)置之后,會(huì)調(diào)用 rtmsg_ifa,傳遞的事件為 RTM_NEWADDR。
清單 2. rtmsg_ifa 發(fā)送 IP 地址變化消息
/* 以下代碼摘自 Linux kernel 2.6.18, net/ipv4/devinet.c 文件 */ static void rtmsg_ifa(int event, struct in_ifaddr* ifa) { int size = NLMSG_SPACE(sizeof(struct ifaddrmsg) + 128); struct sk_buff *skb = alloc_skb(size, GFP_KERNEL); if (!skb) netlink_set_err(rtnl, 0, RTNLGRP_IPV4_IFADDR, ENOBUFS); else if (inet_fill_ifaddr(skb, ifa, 0, 0, event, 0) < 0) { kfree_skb(skb); netlink_set_err(rtnl, 0, RTNLGRP_IPV4_IFADDR, EINVAL); } else { netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV4_IFADDR, GFP_KERNEL); } }
從清單 2 中可以看到,rtmsg_ifa 的實(shí)現(xiàn)主要包括:
首先分配了一塊類型為 struct sk_buff 的空間用于存放需要發(fā)送的消息內(nèi)容。
隨后,調(diào)用 inet_fill_ifaddr 將消息填充至上述緩存(有關(guān)消息的格式,您可以自行查看參考資源)。值得注意的是,RTM_NEWADDR 被作為 nlmsg_type 封裝到了內(nèi)核發(fā)送給應(yīng)用程序的 netlink 消息頭 nlmsghdr 中,這樣用戶空間的應(yīng)用程序在接收后就能夠根據(jù) type 來分別處理不同類型的消息了。
rtmsg_ifa 的最后是調(diào)用了 netlink_broadcast 將上述封裝完畢的 sk_buff 結(jié)構(gòu)廣播到 RTNLGRP_IPV4_IFADDR 這個(gè) group,以下是內(nèi)核空間組播 group 與用戶空間組播 group 的對(duì)應(yīng)關(guān)系:
清單 3. 內(nèi)核空間組播 group 與用戶空間組播 group 的對(duì)應(yīng)關(guān)系
/* 以下代碼摘自 Linux kernel 2.6.18, include/linux/rtnetlink.h 文件 */ /* RTnetlink multicast groups */ enum rtnetlink_groups { RTNLGRP_NONE, #define RTNLGRP_NONE RTNLGRP_NONE RTNLGRP_LINK, #define RTNLGRP_LINK RTNLGRP_LINK ..... RTNLGRP_IPV4_IFADDR, #define RTNLGRP_IPV4_IFADDR RTNLGRP_IPV4_IFADDR ...... }; #ifndef __KERNEL__ /* RTnetlink multicast groups - backwards compatibility for userspace */ #define RTMGRP_LINK 1 #define RTMGRP_NOTIFY 2 ...... #define RTMGRP_IPV4_IFADDR 0x10 ...... #endif
綜上所述,當(dāng)主機(jī)的 IP 地址發(fā)生變化時(shí),內(nèi)核會(huì)向所有 RTNLGRP_IPV4_IFADDR 組播成員發(fā)送 RTM_NEWADDR 消息。因此,在用戶空間創(chuàng)建 netlink 套接字時(shí),只需要加入到 RTMGRP_IPV4_IFADDR 這個(gè)組播 group 中,就可以實(shí)現(xiàn)當(dāng)本機(jī) IP 地址有更新的時(shí)候,DDNS 應(yīng)用程序能夠異步地收到內(nèi)核空間發(fā)來的通知消息了。
用戶空間 netlink socket 的創(chuàng)建、綁定與消息接收處理
用戶空間創(chuàng)建 netlink 套接字
用戶空間的 netlink socket 相關(guān)操作與標(biāo)準(zhǔn) socket API 完全一致,因此可以像使用標(biāo)準(zhǔn) socket 來進(jìn)行兩臺(tái)主機(jī)間的 IP 協(xié)議通信一樣地來使用它,這也是 netlink 之所以能夠得到越來越廣泛應(yīng)用的一個(gè)重要原因。
清單 4. 用戶空間創(chuàng)建 netlink socket
#include <sys/socket.h> #include <linux/types.h> #include <linux/netlink.h> #include <linux/rtnetlink.h> ...... int main(void) { ...... if((nl_socket = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE))==-1) // 指定通信域、通信方式以及通信協(xié)議 exit(1); ...... }
在創(chuàng)建 netlink 套接字時(shí):
我們指定了通信域?yàn)?PF_NETLINK,表明這是一個(gè) netlink 套接字。其定義可以在如下所示的內(nèi)核 include/linux/socket.h 文件中找到。從中我們也可以看到自己非常熟悉的 AF_INET:
清單 5. 清單 4 中使用到的宏定義
/* 以下代碼摘自 include/linux/socket.h 文件 */ /* Supported address families. */ #define AF_UNSPEC 0 #define AF_UNIX 1 /* Unix domain sockets */ #define AF_LOCAL 1 /* POSIX name for AF_UNIX */ #define AF_INET 2 /* Internet IP Protocol */ ...... #define AF_NETLINK 16 ...... /* Protocol families, same as address families. */ #define PF_NETLINK AF_NETLINK ......
對(duì)于通信方式,我們選擇了 SOCK_DGRAM。事實(shí)上對(duì)于 netlink 這種基于無連接的 socket,使用 SOCK_DGRAM 或者 SOCK_RAW 都是可以的。
對(duì)于通信協(xié)議,我們使用了 NETLINK_ROUTE。這是因?yàn)樵谇鍐?1 中,內(nèi)核空間創(chuàng)建 netlink 套接字、用于發(fā)送 IP 地址發(fā)生變化的消息時(shí)使用的是它,所以這里需要保持一致以進(jìn)行雙方間的通信。
用戶空間綁定 netlink 套接字
與標(biāo)準(zhǔn)的 socket 使用方法相似,在建立 netlink 套接字之后,也需要綁定到一個(gè) netlink 地址才能夠進(jìn)行消息的發(fā)送與接收。netlink 地址在 struct sockaddr_nl 結(jié)構(gòu)中定義,各結(jié)構(gòu)成員的含義可參見附錄 3。
清單 6. 用戶空間 bind netlink socket
#include <sys/socket.h> #include <linux/types.h> #include <linux/netlink.h> #include <linux/rtnetlink.h> ...... int main(void) { ...... struct sockaddr_nl addr // 在 include/linux/netlink.h 中定義,結(jié)構(gòu)各成員的含義可參見附錄 3 memset(&addr, 0, sizeof(addr)); addr.nl_family = PF_NETLINK; // 定義協(xié)議簇為 PF_NETLINK addr.nl_groups = RTMGRP_IPV4_IFADDR // 加入到 RTMGRP_IPV4_IFADDR 組播 group 中 addr.nl_pid = 0; // 讓 kernel 來分配 pid ...... // 將清單 5 中創(chuàng)建的 netlink 套接字與上述協(xié)議地址進(jìn)行綁定 if(bind(nl_socket, (struct sockaddr *) &addr, sizeof(addr)) == -1) { close(nl_socket); exit(1); } ...... }
從清單 6 中可以看到,在綁定應(yīng)用程序的 netlink 套接字時(shí),我們將自己加入到了 RTMGRP_IPV4_IFADDR 組播 group 中,這與前文我們對(duì)內(nèi)核空間 IP 地址變化事件的通知過程的分析是一致的。
用戶空間接收并處理內(nèi)核空間消息
同樣與標(biāo)準(zhǔn)的 socket 使用方法類似,用戶空間接收內(nèi)核空間發(fā)來的 netlink 消息可以使用 recv、recvfrom 或 recvmsg。值得一提的是,netlink 套接字有自己的消息頭:nlmsghdr 結(jié)構(gòu)(該結(jié)構(gòu)具體各成員變量的含義請(qǐng)查看參考資源),而其中的 nlmsg_type 正是我們需要用到的包含了消息類型的字段。
清單 7. 用戶空間接收內(nèi)核空間消息
#define MAX_MSG_SIZE 1024 ...... #include <sys/socket.h> #include <linux/types.h> #include <linux/netlink.h> #include <linux/rtnetlink.h> ...... struct if_info { int index; //interface 的序號(hào) char name[IFNAMSIZ]; //interface 的名稱,Linux 內(nèi)核 include/linux/if.h 中定義了 IFNAMSIZ uint8_t mac[ETH_ALEN]; //interface 的 mac 地址,Linux 內(nèi)核 include/linux/if_ether.h 中定義了 ETH_ALEN ...... //interface 的其他信息 struct if_info *next; // 指向下一個(gè) if_info 結(jié)構(gòu)的指針 }; static struct if_info *if_list = NULL; // 存放現(xiàn)有的 interface 列表,在每次程序初始化時(shí)更新 int receive_netlink_message(struct nlmsghdr *nl); // 用于接收內(nèi)核空間發(fā)來的消息的函數(shù) handle_newaddr(struct ifinfomsg *ifi, int len); // 用于處理向 DNS 服務(wù)器發(fā)送更新的函數(shù) ...... int main(void) { ...... int len = 0; struct nlmsghdr *nl; // 結(jié)構(gòu)體定義可以參考內(nèi)核 include/linux/netlink.h 文件 while((len = receive_netlink_message(&nl)) > 0) { while(NLMSG_OK(nl, len)) //NLMSG 相關(guān)的宏定義可以參考內(nèi)核 include/linux/netlink.h 文件 { switch(nl->nlmsg_type) { case RTM_NEWADDR: // 處理 RTM_NEWADDR 的 netlink 消息類型 //ifinfomsg 結(jié)構(gòu)可以參考內(nèi)核 include/linux/rtnetlink.h 文件 handle_newaddr((struct ifinfomsg *)NLMSG_DATA(nl), NLMSG_PAYLOAD(nl, sizeof(struct ifinfomsg))); break; ...... // 處理其他 netlink 消息類型,如:RTM_NEWLINK,這里略過 default: printf("Unknown netlink message type : %d", nl->nlmsg_type); } nl = NLMSG_NEXT(nl, len); } if( nl != NULL ) free(nl); } ...... } int receive_netlink_message(struct nlmsghdr **nl) { struct iovec iov; // 使用 iovec 進(jìn)行接收 struct msghdr msg = {NULL, 0, &iov, 1, NULL, 0, 0}; // 初始化 msghdr int length; *nl = NULL; if ((*nl = (struct nlmsghdr *) malloc(MAX_MSG_SIZE)) == NULL ) return 0; iov.iov_base = *nl; // 封裝 nlmsghdr iov.iov_len = MAX_MSG_SIZE; // 指定長度 length = recvmsg(nl_socket, &msg, 0); if(length <= 0) FREE(*nl); return length; }
應(yīng)用程序在收到了 RTM_NEWADDR 類型的 netlink 消息后,需要根據(jù) IP 的變化進(jìn)行處理。這里使用了 handle_newaddr 函數(shù),對(duì) IP 的變化分為了兩種情況:一種是 interface 已經(jīng)存在、僅僅是 IP 發(fā)生了變化;另一種是 interface 是新添加的。無論是哪種情況,handle_newaddr 函數(shù)在進(jìn)行了相應(yīng)的處理之后,都需要調(diào)用 update_dns.sh 這個(gè)腳本通知 DNS 服務(wù)器。關(guān)于 update_dns.sh 的實(shí)現(xiàn)參見下一章。
清單 8. 用戶空間處理內(nèi)核空間消息
void handle_newaddr(struct ifinfomsg *ifinfo, int len) { struct if_info *i; for(i = if_list ; i ; i = i->next) // 遍歷 in_list,找到 ip 發(fā)生變化的 interface if(i->index == ifinfo->ifi_index) break; if(i != NULL){ // 找到了相應(yīng)的 interface,執(zhí)行 update_dns.sh system(update_dns.sh); return; } // 沒有找到對(duì)應(yīng)的 interface,說明該 interface 是新添加的 if((i = calloc(sizeof(struct if_info), 1)) == NULL)// 分配一個(gè) if_info 結(jié)構(gòu)用于添加新的 interface exit(1); // 根據(jù) ifinfo->ifi_index 等信息更新 if_info 結(jié)構(gòu) i,考慮到與 ddns 應(yīng)用關(guān)系不大,限于篇幅,這里略過 ...... system(update_dns.sh); // 執(zhí)行 update_dns.sh i->next = if_list; // 在 if_list 的末尾添加新發(fā)現(xiàn)的 interface if_list = i; }
應(yīng)用程序與 DNS 服務(wù)器的交互
應(yīng)用程序可以利用開源工具 nsupdate 來向 DNS 服務(wù)器發(fā)送 DNS update 消息。nsupdate 的詳細(xì)用法及特性可以請(qǐng)查看參考資源,受篇幅所限,本章將會(huì)結(jié)合例子簡(jiǎn)單介紹這個(gè)工具的基本用法。
nsupdate 可以從終端或文件中讀取命令,每個(gè)命令一行。一個(gè)空行或一個(gè)"send"命令,則會(huì)將先前輸入的命令發(fā)送到 DNS 服務(wù)器上,典型的使用方法如清單 9 所示。nsupdate 默認(rèn)從文件 /etc/resolv.conf 中解析 DNS 服務(wù)器和域名,在實(shí)際應(yīng)用中,我們可以首先解析網(wǎng)絡(luò)參數(shù),生成 nsupdate 的輸入文件,最后調(diào)用 nsupdate。update_dns.sh 的實(shí)現(xiàn)流程如圖 3 所示。
清單 9. nsupdate 的使用例子
# nsupdate > server 9.0.148.50 //DNS 服務(wù)器地址 9.0.148.50,默認(rèn)端口 53 > update delete oldhost.example.com A // 刪除域名 oldhost.example.com 的任何 A 類型記錄 > update add newhost.example.com 86400 A 172.16.1.1 // 添加一條 172.16.1.1<----->newhost.example.com A 類型的記錄, // 記錄的 TTL 是 24 小時(shí)(86400 秒) > send // 發(fā)送命令
圖 3. update_dns.sh 的實(shí)現(xiàn)流程
netlink socket 的關(guān)閉
用戶空間關(guān)閉 netlink socket
同標(biāo)準(zhǔn)的 socket API 一樣,用戶空間關(guān)閉 netlink socket 使用的也是 close 函數(shù),而且用法完全一致。您可以參考清單 6 中 close 函數(shù)在 DDNS 應(yīng)用程序中的使用。
內(nèi)核空間關(guān)閉 netlink socket
內(nèi)核空間關(guān)閉 netlink socket 使用 sock_release 函數(shù),函數(shù)原型如下所示:
清單 10. 內(nèi)核空間關(guān)閉 netlink socket - sock_release
/* 以下代碼摘自 Linux kernel 3.4.3, net/socket.c 文件 */ void sock_release(struct socket * sock);
其中 sock 為 netlink_kernel_create 創(chuàng)建的 netlink 套接字。
值得一提的是,在最新的 Linux kernel 中,還提供了 netlink_kernel_release 接口,函數(shù)原型如下所示:
清單 11. 內(nèi)核空間關(guān)閉 netlink socket —— netlink_kernel_release
/* 以下代碼摘自 Linux kernel 3.4.3, net/netlink/af_netlink.c 文件 */ void netlink_kernel_release(struct sock *sk);
其中 sk 為 netlink_kernel_create 創(chuàng)建的 netlink 套接字。
對(duì) DDNS 應(yīng)用實(shí)現(xiàn)的擴(kuò)展啟示
DDNS 利用 rtnetlink 的 NETLINK_ROUTE 協(xié)議簇套接字來監(jiān)聽 Linux 內(nèi)核網(wǎng)絡(luò)事件“RTM_NEWADDR”,實(shí)時(shí)更新 DNS 映射信息,從而實(shí)現(xiàn) DNS 信息的動(dòng)態(tài)更新。除了 NETLINK_ROUTE,netlink_family 還提供了多種協(xié)議簇來實(shí)現(xiàn)多種信息的報(bào)告,比如 SELinux、防火墻、Netfilter、IPV6 等。就 NETLINK_ROUTE 協(xié)議簇而言,也提供了多個(gè)組播 group 對(duì)應(yīng)多種網(wǎng)絡(luò)連接、網(wǎng)絡(luò)參數(shù)、路由信息、網(wǎng)絡(luò)流量類別等等變化的事件。
這就啟示我們可以利用 netlink,特別是 rtnetlink,實(shí)現(xiàn)許多其他的與網(wǎng)絡(luò)相關(guān)的應(yīng)用。比如:應(yīng)用程序如果需要實(shí)時(shí)地監(jiān)控本機(jī)路由表的變化,就可以在用戶空間創(chuàng)建 NETLINK_ROUTE 協(xié)議簇的 netlink 套接字時(shí)把自己加到 RTMGRP_IPV4_ROUTE 及 RTMGRP_NOTIFY 的多播組中(即:addr.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_NOTIFY;)通過這種方式,可以實(shí)現(xiàn)包括 OSPF、RIPv2、BGP 等在內(nèi)的多種現(xiàn)行路由協(xié)議;再比如:也可以利用 rtnetlink 來監(jiān)聽網(wǎng)絡(luò)的連接情況,rtnetlink 在初始化的時(shí)候?qū)?rtnetlink 消息處理函數(shù) rtnetlink_event 掛到了通知鏈 netdev_chain 上,網(wǎng)絡(luò)設(shè)備的啟動(dòng),關(guān)閉,更名等事件都能觸發(fā)通知鏈并回調(diào)消息處理函數(shù),從而組播 RTM_NEWLINK 或者 RTM_DELLINK 信息,向用戶程序通知網(wǎng)絡(luò)的連接情況。
總結(jié)
本文結(jié)合 DDNS 的工作原理,簡(jiǎn)單闡釋了 DDNS 的實(shí)現(xiàn)流程,并在此基礎(chǔ)之上,進(jìn)一步演示了利用 Linux rtnetlink 套接字實(shí)現(xiàn)內(nèi)核空間與用戶空間的網(wǎng)絡(luò)狀態(tài) IP 地址變化信息的交互、以及利用 nsupdate 實(shí)現(xiàn) DDNS 客戶端與服務(wù)器端的同步更新,并且在實(shí)際的應(yīng)用中完全實(shí)現(xiàn)了 DDNS 的功能,希望能夠?yàn)槭褂?DDNS 進(jìn)行網(wǎng)絡(luò)管理的人員及 Linux 網(wǎng)絡(luò)編程愛好者提供有益的參考。
參考資料
學(xué)習(xí)
- 參考“在 Linux 下用戶空間與內(nèi)核空間數(shù)據(jù)交換的方式,第 1 部分 : 內(nèi)核啟動(dòng)參數(shù)、模塊參數(shù)與 sysfs、sysctl、系統(tǒng)調(diào)用和 netlink”,了解 Linux 用戶空間與內(nèi)核空間的多種數(shù)據(jù)交換方式,以及它們各自的優(yōu)缺點(diǎn)。
- 參考“Linux 系統(tǒng)內(nèi)核空間與用戶空間通信的實(shí)現(xiàn)與分析”,了解 netlink 套接字在內(nèi)核空間的 API
- 參考 netlink(7) 的 man 手冊(cè),了解 Linux netlink 所支持的包括 NETLINK_ROUTE 在內(nèi)的各種消息類型、消息頭格式、消息地址格式及其用法等等。
- 參考 nsupdate 的 man 手冊(cè),了解開源工具 nsupdate 的詳細(xì)用法與特性
- 在 developerWorks Linux 專區(qū)尋找為 Linux 開發(fā)人員(包括 Linux 新手入門)準(zhǔn)備的更多參考資料。
作者:王 寒芷, 軟件工程師, IBM
王 俊元, 軟件工程師, IBM
相關(guān)文章
使用ssh-keygen,實(shí)現(xiàn)免密碼登陸linux的方法
下面小編就為大家?guī)硪黄褂胹sh-keygen,實(shí)現(xiàn)免密碼登陸linux的方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-11-11centos7 mysql數(shù)據(jù)庫安裝和配置
本篇文章主要介紹了centos7 mysql數(shù)據(jù)庫安裝和配置 ,非常具有實(shí)用價(jià)值,希望對(duì)大家實(shí)用mysql能夠有所幫助2017-01-01Linux (Ubuntu)休眠,掛起,待機(jī),關(guān)機(jī)的命令詳細(xì)介紹
這篇文章主要介紹了Linux 休眠,掛起,待機(jī),關(guān)機(jī)的命令詳細(xì)介紹的相關(guān)資料,需要的朋友可以參考下2016-10-10Linux內(nèi)核設(shè)備驅(qū)動(dòng)之內(nèi)核的時(shí)間管理筆記整理
今天小編就為大家分享一篇關(guān)于Linux內(nèi)核設(shè)備驅(qū)動(dòng)之內(nèi)核的時(shí)間管理筆記整理,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2018-12-12linux新文件權(quán)限設(shè)置之umask的深入理解
這篇文章主要給大家介紹了關(guān)于linux新文件權(quán)限設(shè)置之umask的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03VMware下Centos7橋接方式網(wǎng)絡(luò)配置步驟詳解
這篇文章主要為大家詳細(xì)介紹了VMware下Centos7橋接方式網(wǎng)絡(luò)配置完整步驟,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-06-06