Promiscuous Mode
简介
Monitor mode 与 promiscuous mode 比较
这是在网卡上的的两个特殊的模式,简而言之,都是将网卡的过滤器关闭。
- Monitor mode
这是我们常常提到的sniffer mode。它用于无线网络中,无线网卡开启监听模式,监听空气中的所有数据包,其中它还可以切换channel。如果设置得当,可以同时监控所有信道的帧(切换式,或者同时多个网卡监听)。在这个模式下面,STA是没有连接到AP的。除了能够得到数据包之外,还可以得到控制帧和管理帧。对于debug 802.11的问题(omnipeek or wireshark in linux)或者攻击一个802.11的网络(aircrack、reaver),常常会使网卡进入到这个模式。此文重点在于promiscuous mode,802.11的monitor mode不再赘述。
- Promiscuos mode
不处于promiscuous mode的网卡只会收取DA会自身的数据包或者BC/MC的数据包。在promiscuos mode下面,网卡会收到DA不是自身的包,在进入这个模式的时候,常常会开启一个raw socket,来接收网卡传递上来的数据。
打开promiscuous mode
翻阅libpcap的源码,可以整理出这两种方式,可以打开promiscuous mode:
(activate_new) – new way
1.Try to open a packet socket using the new kernel PF_PACKET interface
2.Select promiscuous mode on
struct packet_mreq mr; memset(&mr, 0, sizeof(mr));
mr.mr_ifindex = handlep->ifindex;
mr.mr_type = PACKET_MR_PROMISC;
sock_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
setsockopt(sock_fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr))
setsockopt 原型如下:
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
对应于内核的 /include/net/sock.h
(setsockopt)(struct sock sk, int level, int optname, char __user *optval, unsigned int optlen);
net/packet/af_packet.c
里面有对应的操作:
static int
packet_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
{
struct sock *sk = sock->sk;
struct packet_sock *po = pkt_sk(sk);
int ret; if (level != SOL_PACKET)
return -ENOPROTOOPT; switch (optname) {
case PACKET_ADD_MEMBERSHIP:
case PACKET_DROP_MEMBERSHIP:
{
struct packet_mreq_max mreq;
int len = optlen;
memset(&mreq, 0, sizeof(mreq));
if (len sizeof(mreq))
len = sizeof(mreq);
if (copy_from_user(&mreq, optval, len))
return -EFAULT;
if (len < (mreq.mr_alen + offsetof(struct packet_mreq, mr_address)))
return -EINVAL;
if (optname == PACKET_ADD_MEMBERSHIP)
ret = packet_mc_add(sk, &mreq);
else
ret = packet_mc_drop(sk, &mreq);
return ret;
}
调用流程:
packet_mc_add -> packet_dev_mc -> dev_set_promiscuity(net/core/dev.c)
dev_set_promiscuity的定义如下:
int dev_set_promiscuity(struct net_device *dev, int inc)
{
unsigned int old_flags = dev->flags;
int err; err = __dev_set_promiscuity(dev, inc, true);
if (err <0 return err if dev->flags != old_flags)
dev_set_rx_mode(dev);
return err;
}
__dev_set_promiscuity =>
dev->flags |= IFF_PROMISC;
dev_change_rx_flags(dev, IFF_PROMISC);
ops(net_device_ops)->ndo_change_rx_flags(dev, flags);
dev_set_rx_mode(dev); ==>
ops(net_device_ops)->ndo_set_rx_mode(dev);
驱动基本上只实现了ndo_set_rx_mode
选择一个Ethernet驱动作为例子:
const struct net_device_ops ei_netdev_ops = {
....
.ndo_open = ei_open,
.ndo_stop = ei_close,
.ndo_start_xmit = ei_start_xmit,
.ndo_set_rx_mode = ei_set_multicast_list,
};
ei_set_multicast_list ->
__ei_set_multicast_list ->
do_set_multicast_list
static void do_set_multicast_list(struct net_device *dev)
{
....
if (dev->flags&IFF_PROMISC) {
memset(ei_local->mcfilter, 0xFF, 8);
ei_outb_p(E8390_RXCONFIG | 0x18, e8390_base + EN0_RXCR);
}
}
这边可以看到驱动设置了EN0_RXCR,含义猜测是RX config register,将RX的接收状态设置为accept all。所以说,设置设备进入promiscuous mode,实际上是设置硬件寄存器ndo_set_rx_mode
,需要设备的驱动支持。
(activate_old) – old way
struct ifreq ifr;
ifr.ifr_flags |= IFF_PROMISC;
ioctl(handle->fd, SIOCSIFFLAGS, &ifr)
这种开启方法,多个开启混杂模式的程序可能会干扰,容易出问题,不推荐使用。
在 net/core/dev_ioctl.c
=> dev_ifsioc
=> dev_change_flags
=> __dev_change_flags
=> dev_set_rx_mode
下面的路径就和上一种方法一样了,不再赘述。可以了解到,在底层的操作,两个做法都是一样的,都是关闭了网卡的过滤器。
如何判断一个机器位于promiscuous mode
既然网卡驱动放行了所有的数据包并且将数据包上传TCPIP协议栈,那么这里可以使用一个技巧。将进入promiscuous mode的主机设为A。从同一网段的B主机伪造一个目标MAC地址不是A,但是目标ip地址是A的包。当正常的主机收到这个包的时候,网卡驱动或者网卡的asic就会将它丢弃,当这个主机进入promiscuous mode之后,网卡驱动放行这个包,TCPIP协议栈检查这个包的目标地址是A,所以会产生一个回应到B主机。当然了,如果主机A特意将TCPIP协议栈的收发包路径关掉,那么就无法侦测到了。
另外,如果我伪造了一个不存在的mac地址,那么交换机就不知道这个mac地址是位于哪个端口,它也会帮忙转发到所有端口。
比如我从B主机伪造一个错误MAC地址的ICMP包给A主机,判断A主机是否回应,这样就可以判断出它是否处于promiscuous mode。
MAC | IP | Payload |
---|---|---|
局域网内没有出现过的mac地址 | 192.168.0.5 | xxxxxxxx |
做一个测试
测试环境: ubuntu 12.4 + win10
测试网卡:Ethernet 网卡
测试软件:wireshark,ICMP c语言测试程序
两端的ip:192.168.0.4,192.168.0.5
测试方式:直连,家用路由器LAN口转发
下面是测试的过程。首先我在目标机器上面(win10)开启了wireshark,并且监听本地连接。这时候我伪造了一个错误的MAC DA,但是其他参数,比如对方的ip地址是填写正确的。这时候本机的wireshark可以看到对方的ICMP回应。紧接着我关闭win10上面的wireshark,ICMP回应消失。随后我又开启wireshark,又可以得到ICMP回应了。测试的时候,两台机器使用网线直连或者通过家用路由器的LAN口转发都是成功的,但是使用无线网络的时候是失败的,可能是无线网卡不支持promiscuous mode。注意到,因为是要伪造MAC地址,所以需要使用PF_PACKET
来操作RAW socket
下图是在ubuntu上面的wireshark截取的
另外,如果两个机器直连测试,需要在windows上面设置静态ip地址(192.168.0.5/24),在linux机器上面关闭界面上的网络连接,并且输入测试网络是否连通:
tanhangbo@ThinkPad:~$ sudo ifconfig eth0 up
tanhangbo@ThinkPad:~$ sudo ifconfig eth0 192.168.0.4
tanhangbo@ThinkPad:~$ ping 192.168.0.5
PING 192.168.0.5 (192.168.0.5) 56(84) bytes of data.
64 bytes from 192.168.0.5: icmp_req=1 ttl=128 time=0.312 ms
64 bytes from 192.168.0.5: icmp_req=2 ttl=128 time=0.384 ms
64 bytes from 192.168.0.5: icmp_req=3 ttl=128 time=0.408 ms
实际作用
一般来说,进入这个模式,就是为了多收一些包,进行网络诊断。一般开启wireshark的时候就会帮你打开promiscuous mode。底层操作在libpcap里面。
- 参考资料:
- libpcap和linux kernel 源码
- http://stackoverflow.com/questions/6666257/what-is-the-purpose-of-net-device-uc-promisc-field
Promiscuous Mode的更多相关文章
- What Is The Promiscuous Mode
What Is The Promiscuous Mode? Some Network Interface Cards (NICs) may not allow network traffic afte ...
- 嵌入式Linux驱动学习之路(二十六)DM9000C网卡驱动程序
基于DM9000C的原厂代码修改dm9000c的驱动程序. 首先确认内存的基地址 iobase. 确定中断号码. 打开模块的初始化函数定义. 配置内存控制器的相应时序(结合DM9000C.C的手册). ...
- 使用SharpPCap在C#下进行网络抓包
在做大学最后的毕业设计了,无线局域网络远程安全监控策略那么抓包是这个系统设计的基础以前一直都是知道用winpcap的,现在网上搜了一下,有用C#封装好了的,很好用下面是其中的几个用法这个类库作者的主页 ...
- Automated Memory Analysis
catalogue . 静态分析.动态分析.内存镜像分析对比 . Memory Analysis Approach . volatility: An advanced memory forensics ...
- Window系统性能获取帮助类
前言: 这个是获取Windows系统的一些性能的帮助类,其中有:系统内存.硬盘.CPU.网络(个人测试还是比较准的).Ping.单个进程的内存.Cpu.网络(不准). 最初在这个的时候在各种搜索 ...
- Python黑帽编程 4.1 Sniffer(嗅探器)之数据捕获(上)
Python黑帽编程 4.1 Sniffer(嗅探器)之数据捕获(上) 网络嗅探,是监听流经本机网卡数据包的一种技术,嗅探器就是利用这种技术进行数据捕获和分析的软件. 编写嗅探器,捕获数据是前置功能, ...
- Netruon 理解(12):使用 Linux bridge 将 Linux network namespace 连接外网
学习 Neutron 系列文章: (1)Neutron 所实现的虚拟化网络 (2)Neutron OpenvSwitch + VLAN 虚拟网络 (3)Neutron OpenvSwitch + GR ...
- SharpPcap网络包捕获框架的使用--实例代码在vs2005调试通过
转自:http://hi.baidu.com/boyxgb/blog/item/89ac86fbdff5f82c4e4aea2e.html 由于项目的需要,要从终端与服务器的通讯数据中获取终端硬件状态 ...
- windows下使用C#获取特定进程网络流量
最近老板接了一个中船重工的项目,需要做一个有关海军软件系统的组件评估项目,项目中有一个子项目需要获取特定进程的各种系统参数,项目使用.NET平台.在获取特定进程各种系统参数时,其它诸如进程ID,进程名 ...
随机推荐
- 把普通对象转换成json格式的对象
1.什么叫做JSON?JSON只是一种数据格式(它不是一种新的数据类型) var obj = {name: "中国", age: 5000};//->普通格式的对象 var ...
- 取出session中的所有属性与值的方法
如果你想取出session中所有的属性和值,可以通过getAttributeNames()方法来实现,具体代码如下 //获取session HttpSession session = request. ...
- javascript 函数初探 (四)--- 回调函数
回调函数 既然函数与任何被赋值给变量的数据是相同的,那么她当然可以像其他数据那样被定义.删除.拷贝,以及当成参数传递给其它函数. 我们定义一个函数,这个函数有两个函数类型的参数,然后他会分别执行这两个 ...
- crm on premise IFD 部署下提供oauth 2.0 集成自定义应用
很多情况下我们的CRM系统会和弟三方应用集成,一般情况我们会开发一个中间站点来提供web api 给弟三方应用. 参考:http://alexanderdevelopment.net/post/201 ...
- 将oracle冷备份恢复到另外一个数据库实例中
因更换服务器需要将Oracle数据库转移到另外台Oracle中.说明: 1.测试环境为:windows server2003 和 oracle 10g. 2.2台服务器安装的程序目录一样,数据目录不一 ...
- Android项目实战(二十四):项目包成jar文件,并且将工程中引用的jar一起打入新的jar文件中
前言: 关于.jar文件: 平时我们Android项目开发中经常会用到第三方的.jar文件. 其实.jar文件就是一个类似.zip文件的压缩包,里面包含了一些源代码,注意的是.jar不包含资源文件(r ...
- iOS 学习 - 22 异步解析 JSON,使用 FMDB 存储,TableView 显示
前提是已经知道了有哪些 key 值 Model 类: .h @interface ListModel : NSObject @property (nonatomic, copy)NSString *t ...
- Lucene 时间排序
在Lucene4.4中,想要实现搜索结果按照时间倒序的效果:如果两个文档得分相同,那么就按照发布时间倒序排列:否则就按照分数排列.这种效果在Lucene4.6中实现起来极其简单,直接利用search接 ...
- HADOOP安装指南-Ubuntu15.10和hadoop2.7.2
Ubuntu15.10中安装hadoop2.7.2安装手册 太初 目录 1. Hadoop单点模式... 2 1.1 安装步骤... 2 0.环境和版本... 2 1.在ubu ...
- DbVisualizer连接hbase
1.添加phoneix驱动 (1).点击Tools--->Driver Manager- (2).新建一个驱动,名称为phoenix(名称随意),选择phoenix的客户端驱动,驱动类如图所示 ...