#include "VrEthMonitor.h" #include "IVrUtils.h" #include #ifndef _WIN32 #include #include #include #include #include #include #include #include #include #include #include #include #endif CVrEthMonitor::CVrEthMonitor() : m_fNotify(nullptr) , m_pParam(nullptr) , m_bRunning(false) { } CVrEthMonitor::~CVrEthMonitor() { } /// @brief /// 开始监控 /// @return 成功返回TRUE int CVrEthMonitor::StartMonitor(NetNotify func, void* pParam) { m_bRunning = true; std::thread runMonitor(std::bind(&CVrEthMonitor::_MonitorTask, this)); runMonitor.detach(); m_fNotify = func; m_pParam = pParam; return SUCCESS; } /// @brief /// 停止监控 void CVrEthMonitor::StopMonitor() { m_bRunning = false; } void CVrEthMonitor::_MonitorTask() { #ifndef _WIN32 int socket_fd; int err = 0; int read_r; struct sockaddr_nl sa; struct nlmsghdr *nh; const int len = 2048; char buff[len]; // signal(SIGINT, intHandler); /*打开NetLink Socket*/ socket_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); setsockopt(socket_fd, SOL_SOCKET, SO_RCVBUF, &len, sizeof(len)); /*设定接收类型并绑定Socket*/ bzero(&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(socket_fd, (struct sockaddr *) &sa, sizeof(sa)); while (m_bRunning) { fd_set readFD; FD_SET(socket_fd, &readFD); struct timeval waitTime = { 5, 0 }; int nCount = select(socket_fd + 1, &readFD, nullptr, nullptr, &waitTime); if (nCount > 0) { read_r = read(socket_fd, buff, sizeof(buff)); for (nh = (struct nlmsghdr *) buff; NLMSG_OK(nh, read_r); nh = NLMSG_NEXT(nh, read_r)) { switch (nh->nlmsg_type) { default: /*收到些奇怪的信息*/ break; case NLMSG_DONE: case NLMSG_ERROR: break; case RTM_NEWLINK: case RTM_DELLINK: _ifinfomsg(nh); break; case RTM_NEWADDR: case RTM_DELADDR: _ifaddrmsg(nh); break; case RTM_NEWROUTE: case RTM_DELROUTE: _rtmsg(nh); break; } } } } close(socket_fd); #endif // !_WIN32 } /// 解析RTA,并存入tb void CVrEthMonitor::_parse_rtattr(struct rtattr **tb, int max, struct rtattr *attr, int len) { #ifndef _WIN32 for (; RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) { if (attr->rta_type <= max) { tb[attr->rta_type] = attr; } } #endif // !_WIN32 } ///显示连接信息 ///当网卡变动的时候触发这个信息,例如插/拔网线,增/减网卡设备,启用/禁用接口等. void CVrEthMonitor::_ifinfomsg(struct nlmsghdr *nh) { #ifndef _WIN32 int len; struct rtattr *tb[IFLA_MAX + 1]; struct ifinfomsg *ifinfo; bzero(tb, sizeof(tb)); ifinfo = (ifinfomsg *)NLMSG_DATA(nh); len = nh->nlmsg_len - NLMSG_SPACE(sizeof(*ifinfo)); _parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifinfo), len); //LOG_DEBUG("%s %s: %s \n", (char *)RTA_DATA(tb[IFLA_IFNAME]), (nh->nlmsg_type == RTM_NEWLINK) ? "NEWLINK" : "DELLINK", (ifinfo->ifi_flags & IFF_LOWER_UP) ? "up" : "down"); std::string sName = (char *)RTA_DATA(tb[IFLA_IFNAME]); if (sName.find("eth") != std::string::npos) { if (ifinfo->ifi_flags & IFF_LOWER_UP) { m_fNotify(sName, NET_STATUS_UP, m_pParam); } else { m_fNotify(sName, NET_STATUS_DOWN, m_pParam); } } #endif // !_WIN32 } ///显示地址信息 ///当地址变动的时候触发这个信息,例如通过DHCP获取到地址后 void CVrEthMonitor::_ifaddrmsg(struct nlmsghdr *nh) { #ifndef _WIN32 int len; struct rtattr *tb[IFA_MAX + 1]; struct ifaddrmsg *ifaddr; char tmp[256]; bzero(tb, sizeof(tb)); ifaddr = (ifaddrmsg *)NLMSG_DATA(nh); len = nh->nlmsg_len - NLMSG_SPACE(sizeof(*ifaddr)); _parse_rtattr(tb, IFA_MAX, IFA_RTA(ifaddr), len); if (tb[IFA_LABEL] != NULL && tb[IFA_ADDRESS] != NULL && nh->nlmsg_type == RTM_NEWADDR) { inet_ntop(ifaddr->ifa_family, RTA_DATA(tb[IFA_ADDRESS]), tmp, sizeof(tmp)); } std::string sName = (char *)RTA_DATA(tb[IFLA_IFNAME]); m_fNotify(sName, NET_STATUS_STATUS_CHANGE, m_pParam); #endif } /** * 显示路由信息 * 当路由变动的时候触发这个信息 */ void CVrEthMonitor::_rtmsg(struct nlmsghdr *nh) { #ifndef _WIN32 int len; struct rtattr *tb[RTA_MAX + 1]; struct rtmsg *rt; char tmp[256]; bzero(tb, sizeof(tb)); rt = (rtmsg *)NLMSG_DATA(nh); len = nh->nlmsg_len - NLMSG_SPACE(sizeof(*rt)); _parse_rtattr(tb, RTA_MAX, RTM_RTA(rt), len); if (tb[RTA_DST] != NULL) { inet_ntop(rt->rtm_family, RTA_DATA(tb[RTA_DST]), tmp, sizeof(tmp)); } if (tb[RTA_SRC] != NULL) { inet_ntop(rt->rtm_family, RTA_DATA(tb[RTA_SRC]), tmp, sizeof(tmp)); } if (tb[RTA_GATEWAY] != NULL) { inet_ntop(rt->rtm_family, RTA_DATA(tb[RTA_GATEWAY]), tmp, sizeof(tmp)); if (nh->nlmsg_type == RTM_NEWROUTE) { m_fNotify("", NET_STATUS_ROUTE_ADD, m_pParam); } else { m_fNotify("", NET_STATUS_ROUTE_DEL, m_pParam); } //system("ip rule add from all lookup main pref 0"); } #endif // !_WIN32 } bool VrCreateEthMonitor(IVrEthMonitor** ppEthMonitor) { CVrEthMonitor* pObj = new CVrEthMonitor; *ppEthMonitor = pObj; return true; }