大部分路由器,CPE都会显示下挂设备列表,即lan侧设备。通常做法是通过读取arp表和DHCP租期文件,以获取lan侧设备的ip,mac,hostname等信息。但这种方式有两个弊端:
1 . arp表有老化时间,意味着arp表不是实时更新的,即可能出现设备已经断开,但arp表还有其IP和MAC的对应信息。导致显示错误。
2 . 通过读取DHCP租期文件获取数据,当设备为桥接模式时,会获取不到任何数据。

解决方法

arp老化时间

此问题可通过arping解决,从arp获取到lan侧设备IP,先通过arping(有的设备会禁ping,使用ping结果不一定准确)测试其是否实时连接,若arping不通,则说明此设备已断开连接。lan设备列表则不显示此IP。

桥接模式

桥接模式下获取不到数据是因为本地DHCP已关闭,LAN侧设备的IP是通过上级路由分配的,本地的DHCP租期文件无任何数据。
由于LAN侧设备与上级路由进行DHCP交互的时候,DHCP包会经过路由器LAN口,所以可通过在LAN口抓取DHCP包,解包获取其IP,MAC等信息。

具体实现

DHCP包格式详情DHCP包格式。
整体思路是添加内核模块,在网口侧抓DHCP Request包,再逐层解析数据包,最后从option中,解析出IP等信息。其中option 12是hostname,option 60是vendor,option 50是requested ip。
解包接口如下:

unsigned int apModeListDhcpHook(void *priv, struct sk_buff *skb, const struct nf_hook_state *state)
{unsigned int isGetIP = 0;unsigned int isGetHostname = 0;unsigned int isGetVendor = 0;unsigned int unUdpLen = 0;unsigned int currentIndex = 0;unsigned int optionLen = 0;unsigned char mac[MAX_MAC_SIZE] = "";unsigned char hostname[MAX_STR_SIZE] = "";unsigned char vendor[MAX_STR_SIZE] = "";unsigned char ip[MAX_IP_SIZE] = "";const unsigned char *ucUdpData = NULL;const struct iphdr *iph = NULL;const struct udphdr *uh = NULL;// 没有in设备if (unlikely(!state->in)){return NF_ACCEPT;}if (__constant_htons(ETH_P_IP) == skb->protocol){iph = ip_hdr(skb);if (unlikely(!iph)){return NF_ACCEPT;}// 非UDP协议if (iph->protocol != IPPROTO_UDP){return NF_ACCEPT;}// 非67端口uh = (struct udphdr *) ((unsigned char *) iph + (iph->ihl << 2));if(__constant_ntohs(67) != uh->dest){return NF_ACCEPT;}// UDP数据开始部分ucUdpData = (unsigned char *)((unsigned char *)uh + 8);unUdpLen = ntohs(uh->len);if (unUdpLen < DHCP_TYPE_OFFSET){return NF_ACCEPT;}// 不是request包if (ucUdpData[DHCP_TYPE_OFFSET] != DHCP_TYPE_REQUEST){return NF_ACCEPT;}// 拷贝macif (0 == memcmp(ucUdpData + DHCP_CLIENT_MAC_OFFSET, FFMAC, MAX_MAC_SIZE)){return NF_ACCEPT;}memset(mac, 0, MAX_MAC_SIZE);memcpy(mac, ucUdpData + DHCP_CLIENT_MAC_OFFSET, MAX_MAC_SIZE);hostnameLen = 0;vendorLen   = 0;memset(hostname, 0, MAX_STR_SIZE);memset(vendor,   0, MAX_STR_SIZE);memset(ip,       0, MAX_IP_SIZE);// 开始遍历option, option是tlv结构,option 12 为 hostname, option 60 为 vendor, option 50 为 requested ipcurrentIndex = DHCP_TYPE_OFFSET + 1;while (currentIndex < unUdpLen){if (12 == ucUdpData[currentIndex]) // option 12, can get hostname{optionLen = ucUdpData[++currentIndex];hostnameLen = optionLen > MAX_STR_SIZE ? MAX_STR_SIZE : optionLen;memcpy(hostname, ucUdpData + currentIndex + 1, hostnameLen);isGetHostname = 1;}else if (50 == ucUdpData[currentIndex]) // option 50, can get client ip{optionLen = ucUdpData[++currentIndex];memcpy(ip, ucUdpData + currentIndex + 1, optionLen > MAX_IP_SIZE ? MAX_IP_SIZE : optionLen);isGetIP = 1;}else if (60 == ucUdpData[currentIndex]) // option 60, can get vendor{optionLen = ucUdpData[++currentIndex];vendorLen = optionLen > MAX_STR_SIZE ? MAX_STR_SIZE : optionLen;memcpy(vendor, ucUdpData + currentIndex + 1, vendorLen);isGetVendor = 1;}else if (255 == ucUdpData[currentIndex]) // option 255, end{break;}else // 其他数据,偏移指针继续遍历{optionLen = ucUdpData[++currentIndex];}currentIndex += (optionLen + 1);// ip 、hostname 、vendor都获取到了,提前退出if (3 == isGetHostname + isGetIP + isGetVendor){break;}}// 有的设备没有字段,加上默认值if (isGetHostname != 1){hostnameLen = strlen("unknow-host");memcpy(hostname, "unknow-host", hostnameLen);}if (isGetVendor != 1){vendorLen = strlen("no-vendor");memcpy(vendor, "no-vendor", vendorLen);}add_client_info_to_list(mac, hostname, vendor, ip);}return NF_ACCEPT;
}

执行结果如下:

DHCP应用——获取下挂设备列表信息相关推荐

  1. 提取光猫_下挂设备_路由器性能

    1.提取光猫信息 #!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2018/5/11 0011 12:50 # @Author : Sx ...

  2. jQuery获取下拉菜单列表的值

    在表单提交的网页中,我们经常使用下拉菜单列表,这篇文章解释了如何获取下拉列表选择的值. 在jQuery中,我们通过使用.val()方法获得下拉列表的选定值. .val()方法主要用于获取表单元素的值, ...

  3. C/C++ 获取目录下的文件列表信息

    在C/C++编程时,需要获取目录下面的文件列表信息. 1.数据结构 struct dirent { long d_ino;                 /* inode number 索引节点号 ...

  4. Linux 命令之 lsusb -- 显示本机的USB设备列表信息

    文章目录 命令介绍 常用选项 命令示例 (一)显示 USB 设备详细信息 命令介绍 lsusb命令用于显示本机的USB设备列表,以及USB设备的详细信息. lsusb命令显示的USB设备信息来自&qu ...

  5. python脚本获取华为边缘设备NPU信息

    华为边缘设备(Atlas500)通过以下命令查询NPU的基本信息 npu-smi info 结果如下: +----------------------------------------------- ...

  6. Android USB Host开发之manager.getDeviceList()获取不到设备列表【转载】

    原文:https://www.2cto.com/kf/201305/211304.html 同样遇到这样的问题,我的Android设备是原道N12C,官方的4.0.3系统,遇到这个问题,后来找了半天找 ...

  7. Android USB Host开发之manager.getDeviceList()获取不到设备列表

    同样遇到这样的问题,我的Android设备是原道N12C,官方的4.0.3系统,遇到这个问题,后来找了半天找到的,现在汇总一下吧: 1.创建 android.hardware.usb.host.xml ...

  8. WinPcap笔记(2):获取设备列表

    通常,编写基于WinPcap应用程序的第一件事情,就是获得已连接的网络适配器列表.WinPcap提供了pcap_findalldevs_ex()函数来实现这个功能:返回一个pcap_if结构的链表,这 ...

  9. WinPcap网络编程入门——1. 获取设备列表

    WinPcap网络编程入门--1. 获取设备列表 系列教程章节直达: Winpcap网络编程入门--1. 获取设备列表: 上节中我们简单介绍了 WinPcap 的相关资料,配置好了开发环境,现在就让我 ...

最新文章

  1. NBT:宏基因组二、三代混合组装软件OPERA-MS
  2. 防止程序重复执行的单元
  3. 原生mysql的批量更新及性能测试
  4. Java与嵌入式数据库SQLite的结合
  5. easypoi导出excel不设置样式_EasyExcel为单个Cell设置样式
  6. Java 异步编程:从 Future 到 Loom
  7. 蓝桥杯2017初赛-9数算式-dfs
  8. esp8266 micropython oled_micropython(4):使用ESP8266 控制 oled 屏幕,并显示 helloworld 字符...
  9. 最大值_Leetcode2 | 滑动窗口最大值(Q239)
  10. Ubuntu16.04下,Firefox每次打开新网页都是以新建Windows而不是Tab的解决方案:
  11. 什么是SQL Server TRIM()函数?
  12. Jsp基本page指令、注释、方法声明,书写规范及注意事项
  13. python-scrapy框架学习笔记
  14. mysql sql中的一些问题,Null与空字符
  15. 关于web页面中mata各种标签的解释
  16. 242.有效的字母异位词
  17. IDEA这些既好用又好玩的三十多个宝贝插件你还不知道吗?
  18. 如何批量将图片转换为 Excel 文档
  19. 从零到一,美芽的技术实战
  20. xman 2018夏solo题

热门文章

  1. angular *Ngif else用法
  2. hive自定义函数UDF的使用方法
  3. 8g内存一般占用多少_4/8/16/32GB 玩游戏多少内存才够用?实测大吃一惊
  4. 通过PS合成金鱼在灯泡里畅游的场景
  5. 内核中的死锁问题--当UHCI遇上OHCI
  6. 照片怎么裁剪多余部分?如何在线裁剪图片?
  7. Spring Boot Security持久化令牌7
  8. Java:1009: 求平均分
  9. redis linux 安装包下载,redis linux安装包
  10. android edittext字数显示不全,Android的EditText字数检测和限制解决办法