linux显示网络状态信息,linux 获取网络状态信息(Rtnetlink)

本文详细介绍了Linux内核的rtnetlink协议,用于用户空间与内核间通信,涉及网络接口、IP地址和路由信息的增删查。主要结构包括ifinfomsg、ifaddrmsg和rtmsg,以及相关的rtattr属性处理。通过示例代码展示了如何解析和处理rtnetlink消息,如接口状态、IP地址和路由变动的监听和打印。
摘要由CSDN通过智能技术生成

一、Rtnetlink

Rtnetlink 允许对内核路由表进行读和更改,它用于内核与各个子系统之间(路由子系统、IP地址、链接参数等)的通信,

用户空间可以通过NET_LINK_ROUTER socket 与内核进行通信,该过程基于标准的netlink消息进行。

一些rtnetlink消息在初始头后有一些可选属性,下面是该属性的结构:

1 struct rtattr {

2 unsigned short rta_len; /*Length of option*/

3 unsigned short rta_type; /*Type of option*/

4 /*Data follows*/

5 };

操作这些属性只可以用RTA_*这些宏来造作

169562501_1_20190828073003113.gif

1 /*Macros to handle rtattributes*/

2

3 /*对齐*/

4 #define RTA_ALIGNTO 4

5 #define RTA_ALIGN(len) ( ((len)+RTA_ALIGNTO-1) & ~(RTA_ALIGNTO-1) )

6

7 /*判断是否为合法的路由属性*/

8 #define RTA_OK(rta,len) ((len) >= (int)sizeof(struct rtattr) && 9 (rta)->rta_len >= sizeof(struct rtattr) && 10 (rta)->rta_len <= (len))

11

12 /*获取下一个rtattr的首地址*/

13 #define RTA_NEXT(rta,attrlen) ((attrlen) -= RTA_ALIGN((rta)->rta_len), 14 (struct rtattr*)(((char*)(rta)) + RTA_ALIGN((rta)->rta_len)))

15

16 /*返回加上 rtattr header的总长度*/

17 #define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))

18

19 /*返回数据对齐的最小值*/

20 #define RTA_SPACE(len) RTA_ALIGN(RTA_LENGTH(len))

21

22 /*返回属性数据部分首地址*/

23 #define RTA_DATA(rta) ((void*)(((char*)(rta)) + RTA_LENGTH(0)))

24

25 /*返回属性数据部分的长度*/

26 #define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0))

27

28 /*****************************************************************29 ******************************************************************/

30 rtnetlink_socket = socket(AF_NETLINK, int socket_type, NETLINK_ROUTE);

31

32 int RTA_OK(struct rtattr *rta, int rtabuflen);

33

34 void *RTA_DATA(struct rtattr *rta);

35

36 unsigned int RTA_PAYLOAD(struct rtattr *rta);

37

38 struct rtattr *RTA_NEXT(struct rtattr *rta, unsigned int rtabuflen);

39

40 unsigned int RTA_LENGTH(unsigned int length);

41

42 unsigned int RTA_SPACE(unsigned int length);

169562501_1_20190828073003113.gif

Rtnetlink 由下面这些消息类型构成(新加在标准的netlink消息上)

(1)#RTM_NEWLINK, RTM_DELLINK, RTM_GETLINK

创建或者删除一个特定的网络接口,或者从一个特定的网络接口上获得信息。

这些消息含有一个ifinfomsg类型的结构,紧跟在后面的是一系列的rtattr结构。

169562501_1_20190828073003113.gif

1 /*****************************************************************2 * Link layer specific messages.3 ****/

4

5 /*struct ifinfomsg6 * passes link level specific information, not dependent7 * on network protocol.8 */

9

10 struct ifinfomsg {

11 unsigned char ifi_family; /*AF_UNSPEC*/

12 unsigned short ifi_type; /*Device type*/

13 int ifi_index; /*Interface index*/

14 unsigned int ifi_flags; /*Device flags*/

15 unsigned int ifi_change; /*change mask*/

16 };

17 /*

18 * ifi_family: 接口地址类型19 * ifi_type: 设备类型20 * ifi_index: 是结构唯一的索引21 * ifi_flags: 设备标志,可以看netdevice 结构22 * ifi_change: 保留值,通常设置为0xFFFFFFFF23 */

24

25 /*

26 ifi_type代表硬件设备的类型:27 ARPHRD_ETHER 10M以太网28 ARPHRD_PPP PPP拨号29 ARPHRDLOOPBACK 环路设备30

31 ifi_flags包含设备的一些标志:32 IFF_UP 接口正在运行33 IFF_BROADCAST 有效的广播地址集34 IFF_DEBUG 内部调试标志35 IFF_LOOPBACK 这是自环接口36 IFF_POINTOPOINT 这是点到点的链路设备37 IFF_RUNNING 资源已分配38 IFF_NOARP 无arp协议,没有设置第二层目的地址39 IFF_PROMISC 接口为杂凑(promiscuous)模式40 IFF_NOTRAILERS 避免使用trailer41 IFF_ALLMULTI 接收所有组播(multicast)报文42 IFF_MASTER 主负载平衡群(bundle)43 IFF_SLAVE 从负载平衡群(bundle)44 IFF_MULTICAST 支持组播(multicast)45 IFF_PORTSEL 可以通过ifmap选择介质(media)类型46 IFF_AUTOMEDIA 自动选择介质47 IFF_DYNAMIC 接口关闭时丢弃地址48

49 Routing attributes(rtattr部分属性,rta_type)50

51 rta_type value type description52 ──────────────────────────────────────────────────────────53 IFLA_UNSPEC - 未说明,未指定的数据54 IFLA_ADDRESS hardware address L2硬件地址55 IFLA_BROADCAST hardware address L2广播地址.56 IFLA_IFNAME asciiz string char型设备名.57 IFLA_MTU unsigned int MTU of the device.58 IFLA_LINK int Link type.59 IFLA_QDISC asciiz string Queueing discipline.60 IFLA_STATS see below struct rtnl_link_stats的设备信息61

62 //用来获取ifinfomsg后面的rtattr结构63 #define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))64 */

169562501_1_20190828073003113.gif

(2)# RTM_NEWADDR, RTM_DELADDR, RTM_GETADDR

添加,删除或者接收一个和接口相关的IP地址的信息。

在linux2.2中,一个网口是可以有多个IP地址信息的。这些消息含有一个ifaddrmsg类型的结构,紧跟在后面的是一系列的rtattr结构。

169562501_1_20190828073003113.gif

1 struct ifaddrmsg {

2 unsigned char ifa_family; /*Address type*/

3 unsigned char ifa_prefixlen; /*Prefixlength of address*/

4 unsigned char ifa_flags; /*Address flags*/

5 unsigned char ifa_scope; /*Address scope*/

6 int ifa_index; /*Interface index*/

7 };

8 /*

9 * ifa_family: 地址类型(通常为AF_INET or AF_INET6))10 * ifa_prefixlen: 地址的地址掩码长度,如果改地址定义在这个family11 * ifa_flags:12 * ifa_scope: 地址的作用域13 * ifa_index: 接口索引与接口地址关联14 */

15

16 /*

17 Attributes (rtattr部分属性,rta_type)18 rta_type value type description19 ─────────────────────────────────────────────────────────────20 IFA_UNSPEC - unspecified.21 IFA_ADDRESS raw protocol address 接口地址 interface address22 IFA_LOCAL raw protocol address 本地地址 local address23 IFA_LABEL asciiz string 接口名称 name of the interface24 IFA_BROADCAST raw protocol address 广播 broadcast address.25 IFA_ANYCAST raw protocol address anycast address26 IFA_CACHEINFO struct ifa_cacheinfo Address information.27

28 */

169562501_1_20190828073003113.gif

(3)#RTM_NEWROUTE, RTM_DELROUTE, RTM_GETROUTE

创建,删除或者获取网络设备的路由信息;这些消息包含一个rtmsg结构,其后跟数目可选的rtattr结构。

对于RTM_GETROUTE,设置rtm_dst_len以及rtm_src_len为0表示获取指定路由表的所有条目(entries)。

其它的成员,除了rtm_table、rtm_protocol,0是通配符

169562501_1_20190828073003113.gif

1 struct rtmsg {

2 unsigned char rtm_family;

3 unsigned char rtm_dst_len;

4 unsigned char rtm_src_len;

5 unsigned char rtm_tos;

6

7 unsigned char rtm_table; /*Routing table id*/

8 unsigned char rtm_protocol; /*Routing protocol; see below*/

9 unsigned char rtm_scope; /*See below*/

10 unsigned char rtm_type; /*See below*/

11

12 unsigned rtm_flags;

13 };

14

15 rtm_type Route type

16 ───────────────────────────────────────────────────────────

17 RTN_UNSPEC unknown route /*位置路由*/

18 RTN_UNICAST a gateway or direct route /*网关或直连路由*/

19 RTN_LOCAL a local interface route /*本地接口路由*/

20 RTN_BROADCAST a local broadcast route (sent as a broadcast) /*本地广播式接收,发送*/

21 RTN_ANYCAST a local broadcast route (sent as a unicast) /*本地单播路由*/

22 RTN_MULTICAST a multicast route /*多播路由*/

23 RTN_BLACKHOLE a packet dropping route /*丢弃*/

24 RTN_UNREACHABLE an unreachable destination /*目标不可达*/

25 RTN_PROHIBIT a packet rejection route /*拒绝*/

26 RTN_THROW continue routing lookup in another table /*不在本表*/

27 RTN_NAT a network address translation rule /*nat*/

28 RTN_XRESOLVE refer to an external resolver (not implemented)

29

30 rtm_protocol Route origin.

31 ───────────────────────────────────────

32 RTPROT_UNSPEC unknown

33 RTPROT_REDIRECT by an ICMP redirect (currently unused) /*通过icmp转发建立路由 (目前没用)*/

34 RTPROT_KERNEL by the kernel /*通过内核建立路由*/

35 RTPROT_BOOT during boot /*启动时建立路由*/

36 RTPROT_STATIC by the administrator /*管理员建立*/

37

38 rtm_scope is the distance to the destination:

39

40 RT_SCOPE_UNIVERSE global route

41 RT_SCOPE_SITE interior route in the local autonomous system

42 RT_SCOPE_LINK route on this link

43 RT_SCOPE_HOST route on the local host

44 RT_SCOPE_NOWHERE destination doesn't exist

45

46 /*用户可用范围*/

47 RT_SCOPE_UNIVERSE ~ RT_SCOPE_SITE are available to the user.

48

49 The rtm_flags have the following meanings:

50

51 RTM_F_NOTIFY if the route changes, notify the user via rtnetlink

52 RTM_F_CLONED route is cloned from another route

53 RTM_F_EQUALIZE a multipath equalizer (not yet implemented)

54

55 rtm_table specifies the routing table

56

57 RT_TABLE_UNSPEC an unspecified routing table /*0 未指定的表*/

58 RT_TABLE_DEFAULT the default table /*253 默认表*/

59 RT_TABLE_MAIN the main table /*254 main 表*/

60 RT_TABLE_LOCAL the local table /*255 local 表*/

61

62 //用户可以使用 RT_TABLE_UNSPEC 到 RT_TABLE_DEFAULT 之间的任意值

63

64 Attributes

65

66 rta_type value type description

67 ──────────────────────────────────────────────────────────────

68 RTA_UNSPEC - ignored.

69 RTA_DST protocol address Route destination address. /*目的*/

70 RTA_SRC protocol address Route source address. /*源地址*/

71 RTA_IIF int Input interface index. /*输入设备 index*/

72 RTA_OIF int Output interface index.

73 RTA_GATEWAY protocol address The gateway of the route /*网关*/

74 RTA_PRIORITY int Priority of route. /*优先级*/

75 RTA_PREFSRC

76 RTA_METRICS int Route metric /*路由metric 值*/

77 RTA_MULTIPATH

78 RTA_PROTOINFO

79 RTA_FLOW

80 RTA_CACHEINFO

169562501_1_20190828073003113.gif

一面是一个具体实例:

169562501_1_20190828073003113.gif

1 /*********************************************************2 * Filename: nl_netinfo.c3 * Author: zhangwj4 * Date:5 * Descripte:6 * Email:7 * Warnning:8 **********************************************************/

9 #include

10 #include

11 #include

12 #include /*See NOTES*/

13 #include

14 #include

15 #include

16 #include

17 #include

18 #include

19 #include

20

21 #define EPOLL_LISTEN_MAX_CNT 256

22 #define EPOLL_LISTEN_TIMEOUT 500

23

24 int g_nlfd = -1;

25 int g_epollfd = -1;

26

27 void parse_rtattr(struct rtattr **tb, int max, struct rtattr *attr, int len)

28 {

29 for (; RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) {

30 if (attr->rta_type <= max) {

31 tb[attr->rta_type] = attr;

32 }

33 }

34 }

35

36 void nl_netroute_handle(struct nlmsghdr *nlh)

37 {

38 int len;

39 struct rtattr *tb[RTA_MAX + 1];

40 struct rtmsg *rt;

41 char tmp[256];

42

43 bzero(tb, sizeof(tb));

44 rt = NLMSG_DATA(nlh);

45 len = nlh->nlmsg_len - NLMSG_SPACE(sizeof(*rt));

46 parse_rtattr(tb, RTA_MAX, RTM_RTA(rt), len);

47 printf("%s:", (nlh->nlmsg_type==RTM_NEWROUTE)?"NEWROUT":"DELROUT");

48 if (tb[RTA_DST] != NULL) {

49 inet_ntop(rt->rtm_family, RTA_DATA(tb[RTA_DST]), tmp, sizeof(tmp));

50 printf("DST: %s", tmp);

51 }

52 if (tb[RTA_SRC] != NULL) {

53 inet_ntop(rt->rtm_family, RTA_DATA(tb[RTA_SRC]), tmp, sizeof(tmp));

54 printf("SRC: %s", tmp);

55 }

56 if (tb[RTA_GATEWAY] != NULL) {

57 inet_ntop(rt->rtm_family, RTA_DATA(tb[RTA_GATEWAY]), tmp, sizeof(tmp));

58 printf("GATEWAY: %s", tmp);

59 }

60 printf("\n");

61 }

62

63 void nl_netifinfo_handle(struct nlmsghdr *nlh)

64 {

65 int len;

66 struct rtattr *tb[IFLA_MAX + 1];

67 struct ifinfomsg *ifinfo;

68

69 bzero(tb, sizeof(tb));

70 ifinfo = NLMSG_DATA(nlh);

71 len = nlh->nlmsg_len - NLMSG_SPACE(sizeof(*ifinfo));

72 parse_rtattr(tb, IFLA_MAX, IFLA_RTA (ifinfo), len);

73

74 printf("%s: %s", (nlh->nlmsg_type==RTM_NEWLINK) ? "NEWLINK" : "DELLINK", (ifinfo->ifi_flags & IFF_UP) ? "up" : "down");

75 if(tb[IFLA_IFNAME]) {

76 printf("%s", RTA_DATA(tb[IFLA_IFNAME]));

77 }

78 printf("\n");

79 }

80

81 void nl_netifaddr_handle(struct nlmsghdr *nlh)

82 {

83 int len;

84 struct rtattr *tb[IFA_MAX + 1];

85 struct ifaddrmsg *ifaddr;

86 char tmp[256];

87

88 bzero(tb, sizeof(tb));

89 ifaddr = NLMSG_DATA(nlh);

90 len =nlh->nlmsg_len - NLMSG_SPACE(sizeof(*ifaddr));

91 parse_rtattr(tb, IFA_MAX, IFA_RTA (ifaddr), len);

92

93 printf("%s", (nlh->nlmsg_type == RTM_NEWADDR)? "NEWADDR":"DELADDR");

94 if (tb[IFA_LABEL] != NULL) {

95 printf("%s", RTA_DATA(tb[IFA_LABEL]));

96 }

97 if (tb[IFA_ADDRESS] != NULL) {

98 inet_ntop(ifaddr->ifa_family, RTA_DATA(tb[IFA_ADDRESS]), tmp, sizeof(tmp));

99 printf("%s", tmp);

100 }

101 printf("\n");

102 }

103

104 void nl_netlink_handle(int fd)

105 {

106 int r_size;

107 socklen_t len = 0;

108 char buff[2048] = {0};

109 struct sockaddr_nl addr;

110 struct nlmsghdr *nlh;

111

112 while(1)

113 {

114 len = sizeof(addr);

115 r_size = recvfrom(fd, (void *)buff, sizeof(buff), 0, (struct sockaddr *)&addr, &len);

116 nlh = (struct nlmsghdr *)buff;

117 for(; NLMSG_OK(nlh, r_size); nlh = NLMSG_NEXT(nlh, r_size))

118 {

119 switch(nlh->nlmsg_type) {

120 case NLMSG_DONE:

121 case NLMSG_ERROR:

122 break;

123 case RTM_NEWLINK: /* */

124 case RTM_DELLINK:

125 nl_netifinfo_handle(nlh);

126 break;

127 case RTM_NEWADDR:

128 case RTM_DELADDR: /* */

129 nl_netifaddr_handle(nlh);

130 break;

131 case RTM_NEWROUTE:

132 case RTM_DELROUTE: /* */

133 nl_netroute_handle(nlh);

134 break;

135 default:

136 break;

137 }

138 }

139 }

140 }

141

142 void epoll_event_handle(void)

143 {

144 int i = 0;

145 int fd_cnt = 0;

146 int sfd;

147 struct epoll_event events[EPOLL_LISTEN_MAX_CNT];

148

149 memset(events, 0, sizeof(events));

150 while(1)

151 {

152 /*wait epoll event*/

153 fd_cnt = epoll_wait(g_epollfd, events, EPOLL_LISTEN_MAX_CNT, EPOLL_LISTEN_TIMEOUT);

154 for(i = 0; i < fd_cnt; i++)

155 {

156 sfd = events[i].data.fd;

157 if(events[i].events & EPOLLIN)

158 {

159 if (sfd == g_nlfd)

160 {

161 nl_netlink_handle(sfd);

162 }

163 }

164 }

165 }

166 }

167

168 int epoll_add_fd(int fd)

169 {

170 struct epoll_event ev;

171

172 ev.data.fd = fd;

173 ev.events = EPOLLIN | EPOLLET;

174

175 if (epoll_ctl(g_epollfd, EPOLL_CTL_ADD, fd, &ev) < 0) {

176 perror("epoll add fd error");

177 return -1;

178 }

179

180 printf("epoll add fd[%d] success\n", fd);

181 return 0;

182 }

183

184 int init_epoll_fd()

185 {

186 int epollfd = -1;

187

188 epollfd = epoll_create(EPOLL_LISTEN_MAX_CNT);

189 if (epollfd < 0) {

190 perror("epoll create failure!...");

191 return -1;

192 }

193 g_epollfd = epollfd;

194

195 printf("epool create fd [%d] success\n", epollfd);

196 return g_epollfd;

197 }

198

199 int init_nl_sockfd()

200 {

201 int ret = 0;

202 int nlfd = -1;

203 struct sockaddr_nl sa;

204

205 /*open a netlink fd*/

206 nlfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);

207 if (nlfd < 0) {

208 perror("create netlink socket failure");

209 return -1;

210 }

211

212 memset(&sa, 0, sizeof(sa));

213 sa.nl_family = AF_NETLINK;

214 sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE;

215

216 /*bind netlink*/

217 ret = bind(nlfd, (struct sockaddr *)&sa, sizeof(sa));

218 if (ret < 0) {

219 perror("bind nlfd error");

220 close(nlfd);

221 return -1;

222 }

223

224 if (epoll_add_fd(nlfd)) {

225 close(nlfd);

226 return -1;

227 }

228 g_nlfd = nlfd;

229

230 printf("netlink create fd [%d] success\n", nlfd);

231 return nlfd;

232 }

233

234

235 int main(int argc, char **argv)

236 {

237 if (init_epoll_fd() < 0) { /*创建epoll 监听fd*/

238 return -1;

239 }

240

241 if (init_nl_sockfd() < 0) { /*创建netlink*/

242 return -1;

243 }

244

245 /*循环接收处理*/

246 epoll_event_handle();

247

248 return 0;

249 }

169562501_1_20190828073003113.gif

参考资料:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值