linux 获取网络状态信息(Rtnetlink)
一、Rtnetlink
Rtnetlink 允许对内核路由表进行读和更改,它用于内核与各个子系统之间(路由子系统、IP地址、链接参数等)的通信,
用户空间可以通过NET_LINK_ROUTER socket 与内核进行通信,该过程基于标准的netlink消息进行。
注:netlink用法在上一篇博文中有提到 http://www.cnblogs.com/wenqiang/p/6306727.html
一些rtnetlink消息在初始头后有一些可选属性,下面是该属性的结构:
- struct rtattr {
- unsigned short rta_len; /* Length of option */
- unsigned short rta_type; /* Type of option */
- /* Data follows */
- };
操作这些属性只可以用RTA_*这些宏来造作
- /* Macros to handle rtattributes */
- /* 对齐 */
- #define RTA_ALIGNTO 4
- #define RTA_ALIGN(len) ( ((len)+RTA_ALIGNTO-1) & ~(RTA_ALIGNTO-1) )
- /* 判断是否为合法的路由属性 */
- #define RTA_OK(rta,len) ((len) >= (int)sizeof(struct rtattr) && \
- (rta)->rta_len >= sizeof(struct rtattr) && \
- (rta)->rta_len <= (len))
- /* 获取下一个rtattr的首地址*/
- #define RTA_NEXT(rta,attrlen) ((attrlen) -= RTA_ALIGN((rta)->rta_len), \
- (struct rtattr*)(((char*)(rta)) + RTA_ALIGN((rta)->rta_len)))
- /* 返回加上 rtattr header的总长度 */
- #define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))
- /* 返回数据对齐的最小值 */
- #define RTA_SPACE(len) RTA_ALIGN(RTA_LENGTH(len))
- /* 返回属性数据部分首地址 */
- #define RTA_DATA(rta) ((void*)(((char*)(rta)) + RTA_LENGTH(0)))
- /*返回属性数据部分的长度 */
- #define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0))
- /*****************************************************************
- ******************************************************************/
- rtnetlink_socket = socket(AF_NETLINK, int socket_type, NETLINK_ROUTE);
- int RTA_OK(struct rtattr *rta, int rtabuflen);
- void *RTA_DATA(struct rtattr *rta);
- unsigned int RTA_PAYLOAD(struct rtattr *rta);
- struct rtattr *RTA_NEXT(struct rtattr *rta, unsigned int rtabuflen);
- unsigned int RTA_LENGTH(unsigned int length);
- unsigned int RTA_SPACE(unsigned int length);
Rtnetlink 由下面这些消息类型构成(新加在标准的netlink消息上)
(1)#RTM_NEWLINK, RTM_DELLINK, RTM_GETLINK
创建或者删除一个特定的网络接口,或者从一个特定的网络接口上获得信息。
这些消息含有一个ifinfomsg类型的结构,紧跟在后面的是一系列的rtattr结构。
- /*****************************************************************
- * Link layer specific messages.
- ****/
- /* struct ifinfomsg
- * passes link level specific information, not dependent
- * on network protocol.
- */
- struct ifinfomsg {
- unsigned char ifi_family; /* AF_UNSPEC */
- unsigned short ifi_type; /* Device type */
- int ifi_index; /* Interface index */
- unsigned int ifi_flags; /* Device flags */
- unsigned int ifi_change; /* change mask */
- };
- /*
- * ifi_family: 接口地址类型
- * ifi_type: 设备类型
- * ifi_index: 是结构唯一的索引
- * ifi_flags: 设备标志,可以看netdevice 结构
- * ifi_change: 保留值,通常设置为0xFFFFFFFF
- */
- /*
- ifi_type代表硬件设备的类型:
- ARPHRD_ETHER 10M以太网
- ARPHRD_PPP PPP拨号
- ARPHRDLOOPBACK 环路设备
- ifi_flags包含设备的一些标志:
- IFF_UP 接口正在运行
- IFF_BROADCAST 有效的广播地址集
- IFF_DEBUG 内部调试标志
- IFF_LOOPBACK 这是自环接口
- IFF_POINTOPOINT 这是点到点的链路设备
- IFF_RUNNING 资源已分配
- IFF_NOARP 无arp协议,没有设置第二层目的地址
- IFF_PROMISC 接口为杂凑(promiscuous)模式
- IFF_NOTRAILERS 避免使用trailer
- IFF_ALLMULTI 接收所有组播(multicast)报文
- IFF_MASTER 主负载平衡群(bundle)
- IFF_SLAVE 从负载平衡群(bundle)
- IFF_MULTICAST 支持组播(multicast)
- IFF_PORTSEL 可以通过ifmap选择介质(media)类型
- IFF_AUTOMEDIA 自动选择介质
- IFF_DYNAMIC 接口关闭时丢弃地址
- Routing attributes(rtattr部分属性,rta_type)
- rta_type value type description
- ──────────────────────────────────────────────────────────
- IFLA_UNSPEC - 未说明,未指定的数据
- IFLA_ADDRESS hardware address L2硬件地址
- IFLA_BROADCAST hardware address L2广播地址.
- IFLA_IFNAME asciiz string char型设备名.
- IFLA_MTU unsigned int MTU of the device.
- IFLA_LINK int Link type.
- IFLA_QDISC asciiz string Queueing discipline.
- IFLA_STATS see below struct rtnl_link_stats的设备信息
- //用来获取ifinfomsg后面的rtattr结构
- #define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
- */
(2)# RTM_NEWADDR, RTM_DELADDR, RTM_GETADDR
添加,删除或者接收一个和接口相关的IP地址的信息。
在linux2.2中,一个网口是可以有多个IP地址信息的。这些消息含有一个ifaddrmsg类型的结构,紧跟在后面的是一系列的rtattr结构。
- struct ifaddrmsg {
- unsigned char ifa_family; /* Address type */
- unsigned char ifa_prefixlen; /* Prefixlength of address */
- unsigned char ifa_flags; /* Address flags */
- unsigned char ifa_scope; /* Address scope */
- int ifa_index; /* Interface index */
- };
- /*
- * ifa_family: 地址类型(通常为AF_INET or AF_INET6))
- * ifa_prefixlen: 地址的地址掩码长度,如果改地址定义在这个family
- * ifa_flags:
- * ifa_scope: 地址的作用域
- * ifa_index: 接口索引与接口地址关联
- */
- /*
- Attributes (rtattr部分属性,rta_type)
- rta_type value type description
- ─────────────────────────────────────────────────────────────
- IFA_UNSPEC - unspecified.
- IFA_ADDRESS raw protocol address 接口地址 interface address
- IFA_LOCAL raw protocol address 本地地址 local address
- IFA_LABEL asciiz string 接口名称 name of the interface
- IFA_BROADCAST raw protocol address 广播 broadcast address.
- IFA_ANYCAST raw protocol address anycast address
- IFA_CACHEINFO struct ifa_cacheinfo Address information.
- */
(3)#RTM_NEWROUTE, RTM_DELROUTE, RTM_GETROUTE
创建,删除或者获取网络设备的路由信息;这些消息包含一个rtmsg结构,其后跟数目可选的rtattr结构。
对于RTM_GETROUTE,设置rtm_dst_len以及rtm_src_len为0表示获取指定路由表的所有条目(entries)。
其它的成员,除了rtm_table、rtm_protocol,0是通配符
- struct rtmsg {
- unsigned char rtm_family;
- unsigned char rtm_dst_len;
- unsigned char rtm_src_len;
- unsigned char rtm_tos;
- unsigned char rtm_table; /* Routing table id */
- unsigned char rtm_protocol; /* Routing protocol; see below */
- unsigned char rtm_scope; /* See below */
- unsigned char rtm_type; /* See below */
- unsigned rtm_flags;
- };
- rtm_type Route type
- ───────────────────────────────────────────────────────────
- RTN_UNSPEC unknown route /*位置路由*/
- RTN_UNICAST a gateway or direct route /* 网关或直连路由 */
- RTN_LOCAL a local interface route /* 本地接口路由 */
- RTN_BROADCAST a local broadcast route (sent as a broadcast) /* 本地广播式接收,发送 */
- RTN_ANYCAST a local broadcast route (sent as a unicast) /* 本地单播路由 */
- RTN_MULTICAST a multicast route /* 多播路由 */
- RTN_BLACKHOLE a packet dropping route /* 丢弃 */
- RTN_UNREACHABLE an unreachable destination /* 目标不可达 */
- RTN_PROHIBIT a packet rejection route /* 拒绝 */
- RTN_THROW continue routing lookup in another table /* 不在本表 */
- RTN_NAT a network address translation rule /* nat */
- RTN_XRESOLVE refer to an external resolver (not implemented)
- rtm_protocol Route origin.
- ───────────────────────────────────────
- RTPROT_UNSPEC unknown
- RTPROT_REDIRECT by an ICMP redirect (currently unused) /* 通过icmp转发建立路由 (目前没用)*/
- RTPROT_KERNEL by the kernel /* 通过内核建立路由 */
- RTPROT_BOOT during boot /* 启动时建立路由 */
- RTPROT_STATIC by the administrator /* 管理员建立 */
- rtm_scope is the distance to the destination:
- RT_SCOPE_UNIVERSE global route
- RT_SCOPE_SITE interior route in the local autonomous system
- RT_SCOPE_LINK route on this link
- RT_SCOPE_HOST route on the local host
- RT_SCOPE_NOWHERE destination doesn't exist
- /* 用户可用范围 */
- RT_SCOPE_UNIVERSE ~ RT_SCOPE_SITE are available to the user.
- The rtm_flags have the following meanings:
- RTM_F_NOTIFY if the route changes, notify the user via rtnetlink
- RTM_F_CLONED route is cloned from another route
- RTM_F_EQUALIZE a multipath equalizer (not yet implemented)
- rtm_table specifies the routing table
- RT_TABLE_UNSPEC an unspecified routing table /* 0 未指定的表 */
- RT_TABLE_DEFAULT the default table /* 253 默认表 */
- RT_TABLE_MAIN the main table /* 254 main 表 */
- RT_TABLE_LOCAL the local table /* 255 local 表 */
- //用户可以使用 RT_TABLE_UNSPEC 到 RT_TABLE_DEFAULT 之间的任意值
- Attributes
- rta_type value type description
- ──────────────────────────────────────────────────────────────
- RTA_UNSPEC - ignored.
- RTA_DST protocol address Route destination address. /* 目的 */
- RTA_SRC protocol address Route source address. /* 源地址 */
- RTA_IIF int Input interface index. /* 输入设备 index */
- RTA_OIF int Output interface index.
- RTA_GATEWAY protocol address The gateway of the route /* 网关 */
- RTA_PRIORITY int Priority of route. /* 优先级 */
- RTA_PREFSRC
- RTA_METRICS int Route metric /* 路由metric 值*/
- RTA_MULTIPATH
- RTA_PROTOINFO
- RTA_FLOW
- RTA_CACHEINFO
一面是一个具体实例:
- /*********************************************************
- * Filename: nl_netinfo.c
- * Author: zhangwj
- * Date:
- * Descripte:
- * Email:
- * Warnning:
- **********************************************************/
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <sys/types.h> /* See NOTES */
- #include <sys/socket.h>
- #include <arpa/inet.h>
- #include <sys/epoll.h>
- #include <linux/netlink.h>
- #include <linux/rtnetlink.h>
- #include <linux/route.h>
- #include <errno.h>
- #define EPOLL_LISTEN_MAX_CNT 256
- #define EPOLL_LISTEN_TIMEOUT 500
- int g_nlfd = -;
- int g_epollfd = -;
- void parse_rtattr(struct rtattr **tb, int max, struct rtattr *attr, int len)
- {
- for (; RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) {
- if (attr->rta_type <= max) {
- tb[attr->rta_type] = attr;
- }
- }
- }
- void nl_netroute_handle(struct nlmsghdr *nlh)
- {
- int len;
- struct rtattr *tb[RTA_MAX + ];
- struct rtmsg *rt;
- char tmp[];
- bzero(tb, sizeof(tb));
- rt = NLMSG_DATA(nlh);
- len = nlh->nlmsg_len - NLMSG_SPACE(sizeof(*rt));
- parse_rtattr(tb, RTA_MAX, RTM_RTA(rt), len);
- printf("%s: ", (nlh->nlmsg_type==RTM_NEWROUTE)?"NEWROUT":"DELROUT");
- if (tb[RTA_DST] != NULL) {
- inet_ntop(rt->rtm_family, RTA_DATA(tb[RTA_DST]), tmp, sizeof(tmp));
- printf("DST: %s ", tmp);
- }
- if (tb[RTA_SRC] != NULL) {
- inet_ntop(rt->rtm_family, RTA_DATA(tb[RTA_SRC]), tmp, sizeof(tmp));
- printf("SRC: %s ", tmp);
- }
- if (tb[RTA_GATEWAY] != NULL) {
- inet_ntop(rt->rtm_family, RTA_DATA(tb[RTA_GATEWAY]), tmp, sizeof(tmp));
- printf("GATEWAY: %s ", tmp);
- }
- printf("\n");
- }
- void nl_netifinfo_handle(struct nlmsghdr *nlh)
- {
- int len;
- struct rtattr *tb[IFLA_MAX + ];
- struct ifinfomsg *ifinfo;
- bzero(tb, sizeof(tb));
- ifinfo = NLMSG_DATA(nlh);
- len = nlh->nlmsg_len - NLMSG_SPACE(sizeof(*ifinfo));
- parse_rtattr(tb, IFLA_MAX, IFLA_RTA (ifinfo), len);
- printf("%s: %s ", (nlh->nlmsg_type==RTM_NEWLINK) ? "NEWLINK" : "DELLINK", (ifinfo->ifi_flags & IFF_UP) ? "up" : "down");
- if(tb[IFLA_IFNAME]) {
- printf("%s", RTA_DATA(tb[IFLA_IFNAME]));
- }
- printf("\n");
- }
- void nl_netifaddr_handle(struct nlmsghdr *nlh)
- {
- int len;
- struct rtattr *tb[IFA_MAX + ];
- struct ifaddrmsg *ifaddr;
- char tmp[];
- bzero(tb, sizeof(tb));
- ifaddr = NLMSG_DATA(nlh);
- len =nlh->nlmsg_len - NLMSG_SPACE(sizeof(*ifaddr));
- parse_rtattr(tb, IFA_MAX, IFA_RTA (ifaddr), len);
- printf("%s ", (nlh->nlmsg_type == RTM_NEWADDR)? "NEWADDR":"DELADDR");
- if (tb[IFA_LABEL] != NULL) {
- printf("%s ", RTA_DATA(tb[IFA_LABEL]));
- }
- if (tb[IFA_ADDRESS] != NULL) {
- inet_ntop(ifaddr->ifa_family, RTA_DATA(tb[IFA_ADDRESS]), tmp, sizeof(tmp));
- printf("%s ", tmp);
- }
- printf("\n");
- }
- void nl_netlink_handle(int fd)
- {
- int r_size;
- socklen_t len = ;
- char buff[] = {};
- struct sockaddr_nl addr;
- struct nlmsghdr *nlh;
- while()
- {
- len = sizeof(addr);
- r_size = recvfrom(fd, (void *)buff, sizeof(buff), , (struct sockaddr *)&addr, &len);
- nlh = (struct nlmsghdr *)buff;
- for(; NLMSG_OK(nlh, r_size); nlh = NLMSG_NEXT(nlh, r_size))
- {
- switch(nlh->nlmsg_type) {
- case NLMSG_DONE:
- case NLMSG_ERROR:
- break;
- case RTM_NEWLINK: /* */
- case RTM_DELLINK:
- nl_netifinfo_handle(nlh);
- break;
- case RTM_NEWADDR:
- case RTM_DELADDR: /* */
- nl_netifaddr_handle(nlh);
- break;
- case RTM_NEWROUTE:
- case RTM_DELROUTE: /* */
- nl_netroute_handle(nlh);
- break;
- default:
- break;
- }
- }
- }
- }
- void epoll_event_handle(void)
- {
- int i = ;
- int fd_cnt = ;
- int sfd;
- struct epoll_event events[EPOLL_LISTEN_MAX_CNT];
- memset(events, , sizeof(events));
- while()
- {
- /* wait epoll event */
- fd_cnt = epoll_wait(g_epollfd, events, EPOLL_LISTEN_MAX_CNT, EPOLL_LISTEN_TIMEOUT);
- for(i = ; i < fd_cnt; i++)
- {
- sfd = events[i].data.fd;
- if(events[i].events & EPOLLIN)
- {
- if (sfd == g_nlfd)
- {
- nl_netlink_handle(sfd);
- }
- }
- }
- }
- }
- int epoll_add_fd(int fd)
- {
- struct epoll_event ev;
- ev.data.fd = fd;
- ev.events = EPOLLIN | EPOLLET;
- if (epoll_ctl(g_epollfd, EPOLL_CTL_ADD, fd, &ev) < ) {
- perror("epoll add fd error");
- return -;
- }
- printf("epoll add fd[%d] success\n", fd);
- return ;
- }
- int init_epoll_fd()
- {
- int epollfd = -;
- epollfd = epoll_create(EPOLL_LISTEN_MAX_CNT);
- if (epollfd < ) {
- perror("epoll create failure!...");
- return -;
- }
- g_epollfd = epollfd;
- printf("epool create fd [%d] success\n", epollfd);
- return g_epollfd;
- }
- int init_nl_sockfd()
- {
- int ret = ;
- int nlfd = -;
- struct sockaddr_nl sa;
- /* open a netlink fd */
- nlfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
- if (nlfd < ) {
- perror("create netlink socket failure");
- return -;
- }
- memset(&sa, , sizeof(sa));
- sa.nl_family = AF_NETLINK;
- sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE;
- /* bind netlink */
- ret = bind(nlfd, (struct sockaddr *)&sa, sizeof(sa));
- if (ret < ) {
- perror("bind nlfd error");
- close(nlfd);
- return -;
- }
- if (epoll_add_fd(nlfd)) {
- close(nlfd);
- return -;
- }
- g_nlfd = nlfd;
- printf("netlink create fd [%d] success\n", nlfd);
- return nlfd;
- }
- int main(int argc, char **argv)
- {
- if (init_epoll_fd() < ) { /* 创建epoll 监听fd */
- return -;
- }
- if (init_nl_sockfd() < ) { /* 创建netlink */
- return -;
- }
- /* 循环接收处理 */
- epoll_event_handle();
- return ;
- }
参考资料:
http://www.man7.org/linux/man-pages/man7/rtnetlink.7.html
http://www.man7.org/linux/man-pages/man3/rtnetlink.3.html
linux 获取网络状态信息(Rtnetlink)的更多相关文章
- Android获取网络状态
Android获取网络状态 学习自 https://developer.android.google.cn/reference/android/net/ConnectivityManager http ...
- [android] android 获取网络连接信息
效果图: 工具类 /** * 获取网络连接信息 * * 根据NetworkInfo可以知道有很多的连接方式和信息 * * ① 当没有任何可用网络的时候,networkinfo为null 判断netw ...
- React Native之Fetch简单封装、获取网络状态
1.Fetch的使用 fetch的使用非常简单,只需传入请求的url fetch('https://facebook.github.io/react-native/movies.json'); 当然是 ...
- [React Native]获取网络状态
使用React Native,可以使用NetInfo API获取手机当前的各个网络状态. componentWillMount() { NetInfo.fetch().done((status)=&g ...
- iOS 获取网络状态
在iOS开发者,获取网络状态比较常用 -(NSString *)getNetWorkStates{ UIApplication *app = [UIApplication sharedApplicat ...
- android开发获取网络状态,wifi,wap,2g,3g.工具类(一)
android开发获取网络状态整理: package com.gzcivil.utils; import android.content.Context; import android.net.Con ...
- 微信小程序 --- 获取网络状态
获取网络状态:wx.getNetworkType btnclick:function(){ wx.getNetworkType({ success:function(res){ console.log ...
- C#获取网络状态
/// <summary> /// 获取网络状态 /// </summary> /// <param name="ip">目标IP地址</ ...
- Linux网络编程之"获取网络天气信息"
需求分析: 1.需要Linux c 网络编程基础, 2.需要了解 http 协议 3.需要天气信息相关api(可以从阿里云上购买,很便宜的!) 4.需要cJSON解析库(因为获取到的天气信息一般是用c ...
随机推荐
- SpriteBuilder中本地化的局限性
最后,App中的(图片)logo仍然保留在英语格式. 未来SpriteBuilder将计划支持本地化资源文件,但是写作该篇的时候估计还没有实现. 你现在必须使用正规的iOS app的国际化技术来支持本 ...
- Erlang Rebar 使用指南之四:依赖管理
Erlang Rebar 使用指南之四:依赖管理 全文目录: https://github.com/rebar/rebar/wiki 本章链接: https://github.com/rebar/re ...
- 高斯混合模型和EM算法
使用期望最大化算法(Expectation-Maximization)来进行密度估计(density estimation). 与k-means一样,给定的训练样本是,我们将隐含类别标签用表示.与k- ...
- Xcode出现may cause a leak非忽略的解决方法
前面提到可以把may cause a leak当成安静的美代码忽略掉,但其实还是有另一种方法滴. 你可以用如下代码替换以消除該警告: [xxx performSelector:_cmd withObj ...
- obj-c编程15[Cocoa实例01]:一个会发声的随机数生成器
哇!终于到了obj-c编程系列的第15篇喽,一路走过来满不容易的哦!(怎么个意思,这才哪到哪啊!),为了能够更好的练习obj-c在Cocoa框架上的编程,接下来会以N篇Cocoa实例的博文来巩固和记忆 ...
- Mac OS X安装native gem提示找不到 dyld_stub_binding_helper
在Mac OS X10.10下sudo gem install curses 返回如下错误: apple@kissAir: ruby_src$sudo gem install curses Passw ...
- Java小技巧输出26个英文字母
相信有的童鞋写到过与字母有关的小东西,是否有写过全部的字母呢?26个这么多字母,一个个打会疯掉.所有咱们可以用一个小技巧使用for循环帮我们把26个字母自动搞出来,大家来瞅一眼把! 使用Java遍历2 ...
- 浅入javascript正则表达式的规则.
今天在看jQuery源码的时候,到处都是正则的用法,一气之下就狠下心来.重新回顾了一下正则.下面是做的笔记.非常浅的入门. /* i:表示不区分大小写 g:表示可以全局配置 m:表示可以多行配置 */ ...
- 初识java——运算符和表达式以及注释
java中有不同的运算符,并且在运算中有着优先级的排序计算,其中++和——的优先级最高,最先计算 运算符注意:1,增量和减量运算符++,——. int a=1++; int b=++1; 其中1++表 ...
- 多台或者集群环境下如何保证spring定时器只执行一个
先说一下我们的系统, 在65和66上分别部署有weblogic节点,共计四个,在项目中我们的定时器会隔一段时间就从其它的五个系统中取数据,这时就出现了问题,本来取一次数据就可以的,现在重复执行了三次, ...