Netlink 介绍(译)
原文地址:http://people.redhat.com/nhorman/papers/netlink.pdf
?
譯文:
1 介紹
在Linux和Unix的眾多發(fā)行版中的網(wǎng)絡(luò)配置功能, 都是編程者事后需求的功能, 導(dǎo)致像添加路由、鄰居表?xiàng)l目和配置接口等功能有著很多雜亂的方法, 比如raw socket, ioctl調(diào)用以及專門(mén)的偽網(wǎng)絡(luò)協(xié)議等方法。在Linux 2.4內(nèi)核中, 開(kāi)發(fā)者努力實(shí)現(xiàn)了一種更標(biāo)準(zhǔn)化的配置網(wǎng)絡(luò)的方法。這種方法被命名為netlink sockets, 它旨在創(chuàng)建一個(gè)適合所有網(wǎng)絡(luò)控制方面的通信框架,雖然建立的netlink子系統(tǒng)不是完善的, 但是這是一種新的網(wǎng)絡(luò)配置方法, 也是可靠的基礎(chǔ)。此文檔旨在介紹如何使用netlink socket族和其實(shí)現(xiàn)的協(xié)議。
? ? 本文假設(shè)讀者有C和socket編程的基礎(chǔ)。
2 Netlink 地址族
2.1 socket創(chuàng)建
netlink地址族使用標(biāo)準(zhǔn)的BSD socket API作為用戶空間程序和內(nèi)核交互的使者。創(chuàng)建一個(gè)netlink套接字和創(chuàng)建其它套接字是類似的方式。
socket fd=socket(AF_NETLINK, SOCK_RAW, protocol);地址族參數(shù)總是AF_NETLINK, 并且類型值總是SOCK_RAW, 唯一可變的參數(shù) 就是協(xié)議protocol域, 此域?qū)?huì)繼續(xù)添加可選項(xiàng), 增加了它的可配置性, 下表是protocol的可選項(xiàng)(來(lái)自linux-2.6.32 kernel)。
#define NETLINK_ROUTE 0 /* Routing/device hook */ #define NETLINK_UNUSED 1 /* Unused number */ #define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */ #define NETLINK_FIREWALL 3 /* Firewalling hook */ #define NETLINK_INET_DIAG 4 /* INET socket monitoring */ #define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */ #define NETLINK_XFRM 6 /* ipsec */ #define NETLINK_SELINUX 7 /* SELinux event notifications */ #define NETLINK_ISCSI 8 /* Open-iSCSI */ #define NETLINK_AUDIT 9 /* auditing */ #define NETLINK_FIB_LOOKUP 10 #define NETLINK_CONNECTOR 11 #define NETLINK_NETFILTER 12 /* netfilter subsystem */ #define NETLINK_IP6_FW 13 #define NETLINK_DNRTMSG 14 /* DECnet routing messages */ #define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */ #define NETLINK_GENERIC 16 /* leave room for NETLINK_DM (DM Events) */ #define NETLINK_SCSITRANSPORT 18 /* SCSI Transports */ #define NETLINK_ECRYPTFS 19#define NETLINK_L2TP 20#if defined(CONFIG_RTL_819X) #define NETLINK_RTK_DEBUG 21 #define NETLINK_RTK_FILTER 22 #define NETLINK_MULTICAST_DELETE 23 #define NETLINK_RTK_FB 24 #define NETLINK_RTK_HW_QOS 25 #endif2.2 發(fā)送和接收數(shù)據(jù)包
netlink套接字是無(wú)連接的, 收發(fā)的數(shù)據(jù)報(bào)就表示類似UDP套接字, 發(fā)送數(shù)據(jù)報(bào)通過(guò)sendto或者sendmsg系統(tǒng)調(diào)用, 用recvfrom或者recvmsg接收數(shù)據(jù)報(bào)。 注意, netlink套接字不使用send和recv交互, 這是因?yàn)閚etlink套接字是無(wú)連接的。就像UDP套接字, netlink消息是數(shù)據(jù)報(bào)格式, 雖然netlink消息頭部有一些機(jī)制設(shè)計(jì)用于編程者增加協(xié)議的可靠性, 但仍舊不能保證連接是可靠的。
2.3 netlink套接字地址結(jié)構(gòu)
struct sockaddr_nl 是它的地址結(jié)構(gòu), 用于netlink套接字的接收和發(fā)送, 定義如下:
struct sockaddr_nl {sa_family_t nl_family; /* AF_NETLINK */unsigned short nl_pad; /* zero */__u32 nl_pid; /* port ID */__u32 nl_groups; /* multicast groups mask */ };- nl_family:此域定義了消息的地址族, 應(yīng)該總是AF_NETLINK
- nl_pad? ?: 總是為0
- nl_pid : 一般設(shè)置為本進(jìn)程的pid或者填0理, 如果是進(jìn)程接收來(lái)自內(nèi)核netlink消息, 此域應(yīng)為本進(jìn)程PID,? 如果是向內(nèi)核發(fā)送netlink消息, 此域應(yīng)置0
- nl_groups :用于指定多播組, 如對(duì)接收來(lái)自內(nèi)核的netlink消息來(lái)說(shuō), 內(nèi)核可將要發(fā)送的消息指定一個(gè)多播組, 那么此消息就會(huì)發(fā)向同一多播組的接收端。而對(duì)于進(jìn)程發(fā)送消息來(lái)講, 設(shè)置了多播組就只會(huì)發(fā)送到此多播組的內(nèi)核接收端。此域是32位, 最多可支持32個(gè)多播組。
3 Netlink 消息格式
? 與每個(gè)IP消息頭一樣, netlink消息也有類似的頭部, 然而和其他協(xié)議不同的是, 編程者需要為每個(gè)數(shù)據(jù)包構(gòu)建這個(gè)頭部(一般的TCP/UDP socket都是直接操作報(bào)文的payload部分), 這個(gè)頭部用來(lái)保存每個(gè)消息和格式的元數(shù)據(jù), 這個(gè)頭部也是netlink協(xié)議的基礎(chǔ)。
struct nlmsghdr {u32 nlmsg_len;u16 nlmsg_type;u16 nlmsg_flags;u32 nlmsg_seq;u32 nlmsg_pid; }- nlmsg_len:每個(gè)netlink頭后面跟隨者0個(gè)或者多個(gè)字節(jié)的輔助數(shù)據(jù), 此域記錄了消息的整個(gè)長(zhǎng)度, 包括了頭部在內(nèi)。
- nlmsg_type:此域標(biāo)識(shí)了頭部后面數(shù)據(jù)的格式。此域的取值和2.1中的protocol有關(guān)。
- nlmsg_flags:此域標(biāo)識(shí)了消息由誰(shuí)進(jìn)行處理和解析, 有如下取值 NLM_F_REQUEST - 這個(gè)標(biāo)志暗示這是一個(gè)請(qǐng)求消息, 它應(yīng)該被設(shè)置到大多數(shù)應(yīng)用程序的初始化消息中。 NLM_F_ACK - 這個(gè)標(biāo)志暗示對(duì)前一個(gè)請(qǐng)求消息的回應(yīng), 序列號(hào)和pid值能夠辨別請(qǐng)求的回應(yīng)報(bào)文。 NLM_F_ECHO - 這個(gè)標(biāo)志表示發(fā)出的報(bào)文將回響給發(fā)送進(jìn)程一份。 NLM_F_MULTI - 這個(gè)標(biāo)志表示此消息是多個(gè)消息的一部分, 可用宏NLMSG_NEXT獲得下一個(gè)消息。 NLM_F_ROOT - 用于請(qǐng)求多個(gè)netlink消息, 有此標(biāo)志的請(qǐng)求消息表示請(qǐng)求回復(fù)整個(gè)條目表而不是一條, 回復(fù)的報(bào)文通常是 NLM_F_MULTI標(biāo)志的。注意:此標(biāo)志只適合特定的nlmsg_type才有效。 NLM_F_ATOMIC - 標(biāo)志任何通過(guò)get-->回復(fù)報(bào)文的過(guò)程都是原子的, 防止在中間有資源改變引起歧義。 NLM_F_REPLACE - 替換條目表中的一條, 可用于覆蓋條目表。 NLM_F_CREATE - 在條目表中設(shè)置一個(gè)新的條目(比如添加一條新路由) NLM_F_APPEND - 在條目表末尾添加一個(gè)條目 NLM_F_EXCL - 結(jié)合了CREATE和APPEND, 如果要添加的條目已存在將返回錯(cuò)誤(推薦使用)
-
nlmsg_seq:seq用來(lái)聯(lián)系請(qǐng)求和回復(fù)報(bào)文, 順序標(biāo)志的作用
- nlmsg_pid:和seq類似
3.2 netlink 實(shí)用宏
#define NLMSG_ALIGNTO 4/* 返回不小于len的以4字節(jié)對(duì)齊的最近數(shù)字 (ex: len=9 --> 返回值為12)*/ #define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
/* 返回netlink消息頭的字節(jié)數(shù), 且務(wù)必是以4字節(jié)對(duì)齊的 */ #define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
/* 返回'len + netlink消息頭長(zhǎng)度' 一般len指定為消息的payload長(zhǎng)度, 此宏可用來(lái)填充nlmsg_len域 */ #define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(NLMSG_HDRLEN))
/* 返回值同 NLMSG_LENGTH 宏一樣有效, 主要是確保整個(gè)netlink消息長(zhǎng)度4字節(jié)對(duì)齊(nlmsg_len域是否最好用此域來(lái)填充) */ #define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
/* 返回指向netlink消息payload處的指針(nlh 參數(shù)一般是指向struct nlmsghdr結(jié)構(gòu)的指針) */
#define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0))) ----------------------------- | struct nlmsghdr | payload | -----------------------------|NLMSG_DATA(nlh)
/* 返回指向下一個(gè)netlink消息的指針 */ /* 很多netlink回應(yīng)由多個(gè)netlink消息組成 */ *參數(shù):nlh --> 指向struct nlmsghdr結(jié)構(gòu)的指針len --> 一般為recvmsg函數(shù)的返回值(整個(gè)消息的長(zhǎng)度) #define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \(struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len))) --------------------------------------------------------- | struct nlmsghdr | payload | struct nlmsghdr | payload | --------------------------------------------------------- | | nlh |NLMSG_NEXT(nlh,len)|--------------------------len--------------------------| *此宏先用len(整個(gè)消息的長(zhǎng)度)減掉第一個(gè)消息的長(zhǎng)度, 如果為0, 表示沒(méi)有下一個(gè)消息了, 返回空, 若為非0, 表示后邊還有消息, 指針移動(dòng)指向下一個(gè)消息處并返回.
/* 確保nlh指向的消息大小不大于len */ *參數(shù):nlh --> 指向struct nlmsghdr結(jié)構(gòu)的指針len --> 一般為recvmsg函數(shù)的返回值 #define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \(nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \(nlh)->nlmsg_len <= (len))
?3.3 總結(jié)
下圖是netlink消息的內(nèi)存分布圖:
4?NETLINK_FIREWALL 協(xié)議
由3可知, netlink消息頭nlmsg_type成員的取值和2.1中的protocol有關(guān), 現(xiàn)在就介紹protocol為NETLINK_FIREWALL時(shí)的情況。
這個(gè)協(xié)議是非常有用的開(kāi)發(fā)協(xié)議。首先它是有意被設(shè)計(jì)來(lái)在用戶空間來(lái)調(diào)試iptables模塊的架構(gòu),這個(gè)協(xié)議與很多iptables模塊相關(guān)聯(lián)。ip-queue模塊就是其中一個(gè)(詳見(jiàn):http://blog.csdn.net/u010807313/article/details/9236581),在創(chuàng)建此協(xié)議的netlink套接字之前都需要先安裝相關(guān)模塊,發(fā)往相關(guān)模塊的報(bào)文都會(huì)同樣發(fā)給由NETLINK_FIREWALL協(xié)議創(chuàng)建的netlink套接字, 由此實(shí)現(xiàn)在用戶空間監(jiān)聽(tīng)流經(jīng)netfilter的報(bào)文的目的。例如:
iptables -I OUTPUT -j QUEUE -p tcp –destination-port 7551上面一條命令表示在OUTPUT鏈上, 發(fā)往端口7551的TCP報(bào)文都交給QUEUE鏈來(lái)處理, 而ip-queue模塊正好和NETLINK_FIREWALL協(xié)議的套接字關(guān)聯(lián)(內(nèi)核實(shí)現(xiàn)的), 所以套接字同樣也會(huì)收到這樣的報(bào)文, 實(shí)現(xiàn)了監(jiān)聽(tīng)的目的, 自行修改iptables命令可達(dá)到監(jiān)聽(tīng)多種類型報(bào)文的目的。
4.1 創(chuàng)建和使用
socket fd=socket(AF_NETLINK, SOCK_RAW, NETLINK_FIREWALL);此協(xié)議沒(méi)有使用多播組, 所以地址結(jié)構(gòu)struct sockaddr_nl中的nl_groups應(yīng)該總是設(shè)置為0,并且此協(xié)議的套接字不需要bind函數(shù),因?yàn)閳?bào)文只是在進(jìn)程和內(nèi)核中傳輸,所以從進(jìn)程發(fā)向內(nèi)核的報(bào)文struct sockaddr_nl中的nl_pid應(yīng)該設(shè)置為0。
4.2 消息類型
NETLINK_FIREWALL協(xié)議的套接字有三種消息類型(如3中所述, 成員nlmsg_type的取值),每個(gè)消息類型都有它各自的數(shù)據(jù)結(jié)構(gòu)來(lái)描述。
- IPQM_MODE
- IPQM_PACKET < 這個(gè)是內(nèi)核向用戶空間返回的報(bào)文類型 >
- IPQM_VERDICT
4.2.1 IPQM_MODE
此類型是使用NETLINK_FIREWALL協(xié)議需要第一個(gè)發(fā)向內(nèi)核的包, 內(nèi)核收到之后才會(huì)將匹配的報(bào)文從內(nèi)核發(fā)至用戶空間的netlink套接字。此報(bào)文的數(shù)據(jù)結(jié)構(gòu)如下, 它是緊隨在struct nlmsghdr之后的:
typedef struct ipq mode msg {unsigned char value;size t range; };value的取值有三種:
- IPQ_COPY_NONE - 不常用, 設(shè)置此值發(fā)給內(nèi)核將導(dǎo)致iptables將所有到QUEUE鏈的報(bào)文丟棄。
- IPQ_COPY_META - 表示我希望內(nèi)核返回報(bào)文的元數(shù)據(jù)(我理解是struct nlmsghdr + struct ipq_packet_msg 兩個(gè)頭部)部分。
- IPQ_COPY_PACKET - 表示希望內(nèi)核返回報(bào)文, 報(bào)文長(zhǎng)度由range控制, 若range為0表示返回整個(gè)報(bào)文。如果你需要在用戶空間分析流經(jīng)QUEUE鏈的報(bào)文應(yīng)該設(shè)置此項(xiàng)并將range設(shè)置為0。
range:
此域只在value = IPQ_COPY_PACKET時(shí)才有效。
也就是說(shuō), 用戶進(jìn)程使用IPQM_MODE類型的報(bào)文告訴內(nèi)核, 我需要你返回給我的報(bào)文是什么樣的(不需要 or 要元數(shù)據(jù) or 要range長(zhǎng)的報(bào)文)
4.2.2 IPQM_PACKET
這個(gè)類型的報(bào)文是根據(jù)4.2.1之后內(nèi)核根據(jù)需求返回的報(bào)文。只要之前設(shè)置的value不是IPQ_COPY_NONE, socket就會(huì)收到此類型的報(bào)文, 結(jié)構(gòu)如下:
typedef struct ipq packet msg {unsigned long packet_id;unsigned long mark;long timestamp sec;long timestamp usec;unsigned int hook;char indev name[IFNAMSIZ];char outdev name[IFNAMSIZ];unsigned short hw_protocol;unsigned short hw_type;unsigned char hw_addrlen;unsigned char hw_addr[8];size t data len;unsigned char payload[0]; };- packet_id - 這個(gè)是內(nèi)核產(chǎn)生的獨(dú)一無(wú)二的標(biāo)識(shí), 在4.2.3中發(fā)送IPQM_VERDICT報(bào)文需要。
- mark - //
- timestap_sec - 報(bào)文抵達(dá)時(shí)間(秒)
- timestap_usec - 報(bào)文抵達(dá)時(shí)間(微秒)
- hook - 報(bào)文被重定向到QUEUE的hook number
- indev_name - //
- outdev_name - //
- hw_protocol - 通常是ETH_P_IP
- hw_type - 通常是ARPHDR_ETHER
- hw_addrlen - 通常為6
- hw_addr - 報(bào)文的源MAC地址
- data_len - payload數(shù)據(jù)長(zhǎng)度
- payload - 柔性數(shù)組頭部, 指向了payload數(shù)據(jù)的頭部
4.2.3 IPQM_VERDICT
此類型的報(bào)文是在收到內(nèi)核的回復(fù)報(bào)文之后, 用戶經(jīng)過(guò)自己的檢測(cè), 決定對(duì)此報(bào)文執(zhí)行何種操作, IPQM_MODE --> IPQM_PACKET <----> IPQM_VERDICT, 是順序的過(guò)程。也就是說(shuō), 只有你向內(nèi)核發(fā)送IPQM_VERDICT說(shuō)明了報(bào)文處理方式之后, 你才能recvmsg下一個(gè)到達(dá)QUEUE鏈的報(bào)文, 否則recvmsg會(huì)一直阻塞。結(jié)構(gòu)如下:
typedef struct ipq verdict msg {unsigned int value;unsigned long id;size t data_len;unsigned char payload; };value 指示了對(duì)報(bào)文的處理方式:
- NF_DROP - 立即丟棄報(bào)文
- NF_ACCEPT - 接收?qǐng)?bào)文(不參與之后的iptables鏈了)
- NF_STOLEN - //
- NF_QUEUE - 不常使用
- NF_REPEAT - 將報(bào)文移入下一個(gè)iptables鏈
id - 指示了要對(duì)哪個(gè)報(bào)文進(jìn)行處理, 對(duì)應(yīng)4.2.2的packet_id成員, 這個(gè)成員唯一關(guān)聯(lián)了一個(gè)進(jìn)入QUEUE的報(bào)文
data_len - 指verdict報(bào)文的payload數(shù)據(jù)長(zhǎng)度, 因?yàn)関erdict是用戶發(fā)向內(nèi)核的, 此域一般設(shè)置為0
payload - //
5?NETLINK_ROUTE 協(xié)議
5.1 創(chuàng)建和使用
socket fd=socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);NETLINK_ROUTE協(xié)議是netlink套接字最大且是最成熟的協(xié)議, 它有它自己消息的處理宏(類似3.2節(jié)), 這些NETLINK_ROUTE的宏是為了添加它的輔助數(shù)據(jù)段和定制化特別的消息類型而做的。
每個(gè)族都有同樣的命名空間和輔助數(shù)據(jù)結(jié)構(gòu), 輔助數(shù)據(jù)結(jié)構(gòu)后又跟著一個(gè)或多個(gè)消息。
每個(gè)族都包含三個(gè)方法, NEW, DEL, GET; 這些方法用于創(chuàng)建、刪除和接收路由相關(guān)條目。
5.2 NETLINK_ROUTE消息宏
NETLINK_ROUTE消息實(shí)際有自己的數(shù)據(jù)結(jié)構(gòu), 如下所示。
struct rtattr {unsigned short rta_len;unsigned short rta_type; }下面是NETLINK_ROUTE的消息內(nèi)存布局:
對(duì)于struct rtattr結(jié)構(gòu), 與netlink消息頭struct nlmsghdr結(jié)構(gòu)相似, 有一些宏進(jìn)行輔助處理, 參考3.2節(jié)。
? int RTA OK(struct rtattr *rta, int rtabuflen); - Verify the data integrity of the data which succedes this rtattr header. ? void * RTA DATA(struct rtattr *rta); - Return a pointer to the ancilliary data associated with this rtattr header. ? struct rtattr *RTA NEXT(struct rtattr *rta); - Return a pointer to the next rtattr header in the chain. ? unsigned int RTA PAYLOAD(struct rtattr *rta); - Return the length of the ancilliary data associated with the passed rtattr header. ? unsigned int RTA LENGTH(unsigned int length); - Return the aligned length for the passed payload length. This value is assigned to the rta len field of the rtattr header ? unsigned int RTA SPACE(unsigned int length); - Return the length of the ancilliary data, when aligned.5.3 消息類型
在使用NETLINK_ROUTE協(xié)議的情況下, netlink控制塊struct nlmsghdr中的nlmsg_type域標(biāo)識(shí)了多種消息類型,舉例如下:
5.3.1 LINK消息
LINK消息族允許設(shè)置和獲取關(guān)于系統(tǒng)接口的消息nlmsg_type有如下取值:
- RTM_NEWLINK? - 創(chuàng)建一個(gè)新接口/有一個(gè)新接口被創(chuàng)建
- RTM_DELLINK? ?- 刪除一個(gè)接口
- RTM_GETLINK? - 接收一個(gè)接口消息
每個(gè)消息的輔助數(shù)據(jù)結(jié)構(gòu)是struct ifinfomsg:
struct ifinfomsg {unsigned char ifi_family;unsigned short ifi_type;int ifi index;unsigned int ifi_flags;unsigned int ifi_change; };5.3.2 LINK消息struct rtattr結(jié)構(gòu)rta_type取值
5.3.3 LINK消息內(nèi)存布局
5.4 其它消息類型
比如ADDR消息, ROUTE消息等和LINK消息類似, 不同的是它們有各自的struct ifinfomsg消息和支持不同的rta_type。??
轉(zhuǎn)載于:https://www.cnblogs.com/Flychown/p/8065649.html
總結(jié)
以上是生活随笔為你收集整理的Netlink 介绍(译)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 洛谷 P1583 魔法照片
- 下一篇: script 有哪个属性可以让它不立即执