简介

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里面。

  • 参考资料:
  1. libpcap和linux kernel 源码
  2. http://stackoverflow.com/questions/6666257/what-is-the-purpose-of-net-device-uc-promisc-field

Promiscuous Mode的更多相关文章

  1. What Is The Promiscuous Mode

    What Is The Promiscuous Mode? Some Network Interface Cards (NICs) may not allow network traffic afte ...

  2. 嵌入式Linux驱动学习之路(二十六)DM9000C网卡驱动程序

    基于DM9000C的原厂代码修改dm9000c的驱动程序. 首先确认内存的基地址 iobase. 确定中断号码. 打开模块的初始化函数定义. 配置内存控制器的相应时序(结合DM9000C.C的手册). ...

  3. 使用SharpPCap在C#下进行网络抓包

    在做大学最后的毕业设计了,无线局域网络远程安全监控策略那么抓包是这个系统设计的基础以前一直都是知道用winpcap的,现在网上搜了一下,有用C#封装好了的,很好用下面是其中的几个用法这个类库作者的主页 ...

  4. Automated Memory Analysis

    catalogue . 静态分析.动态分析.内存镜像分析对比 . Memory Analysis Approach . volatility: An advanced memory forensics ...

  5. Window系统性能获取帮助类

    前言: 这个是获取Windows系统的一些性能的帮助类,其中有:系统内存.硬盘.CPU.网络(个人测试还是比较准的).Ping.单个进程的内存.Cpu.网络(不准).    最初在这个的时候在各种搜索 ...

  6. Python黑帽编程 4.1 Sniffer(嗅探器)之数据捕获(上)

    Python黑帽编程 4.1 Sniffer(嗅探器)之数据捕获(上) 网络嗅探,是监听流经本机网卡数据包的一种技术,嗅探器就是利用这种技术进行数据捕获和分析的软件. 编写嗅探器,捕获数据是前置功能, ...

  7. Netruon 理解(12):使用 Linux bridge 将 Linux network namespace 连接外网

    学习 Neutron 系列文章: (1)Neutron 所实现的虚拟化网络 (2)Neutron OpenvSwitch + VLAN 虚拟网络 (3)Neutron OpenvSwitch + GR ...

  8. SharpPcap网络包捕获框架的使用--实例代码在vs2005调试通过

    转自:http://hi.baidu.com/boyxgb/blog/item/89ac86fbdff5f82c4e4aea2e.html 由于项目的需要,要从终端与服务器的通讯数据中获取终端硬件状态 ...

  9. windows下使用C#获取特定进程网络流量

    最近老板接了一个中船重工的项目,需要做一个有关海军软件系统的组件评估项目,项目中有一个子项目需要获取特定进程的各种系统参数,项目使用.NET平台.在获取特定进程各种系统参数时,其它诸如进程ID,进程名 ...

随机推荐

  1. 转载 【CSS进阶】伪元素的妙用--单标签之美

    1.单个颜色实现按钮 hover .active 的明暗变化 请点击 转载利用伪元素单个颜色实现 hover 和 active 时的明暗变化效果 2.利用after伪类清除浮动 .clearfix:a ...

  2. JS全屏漂浮广告、移入光标停止移动

    点击这里查看效果 以下是代码: <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Ty ...

  3. WePayUI 快快尝鲜体验

    好久没有更新博客了... 时间真的很快~~~ 不废话了..干货会直接上~~~ WePayUI是什么 WePayUI 由微信支付为服务商和商户量身打造,用于快速制作符合微信支付规范的Web页面.WePa ...

  4. 使用jq插入节点

    .append()和.appendTo()两种方法功能相同,主要的不同是语法——内容和目标的位置不同 append()前面是要选择的对象,后面是要在对象内插入的元素内容 appendTo()前面是要插 ...

  5. Java语言面向对象的一些基本特点

    封装 1. 面向对象语言使用class封装属性和方法. 2. 属性一般要求定义为private,封装保护 继承. 继承的例子随处可见.需要符合is-a关系,父类更加通用,子类更加具体.. 在子类中使用 ...

  6. Sharepoint学习笔记—习题系列--70-573习题解析 -(Q136-Q138)

    Question 136You need to create a custom content type and specify the content type ID.What should you ...

  7. 【转】linux 定时执行shell脚本

    在oracle 中可以利用dbms_job包定时执行pl/sql.sql过程,在像备份等需要在操作系统级定时任务只能采用crontab来完成 本文讲述crontab具体用法,以供备忘. 在oracle ...

  8. Android高效计算——RenderScript(一)

    高效计算——RenderScript RenderScript是安卓平台上很受谷歌推荐的一个高效计算平台,它能够自动把计算任务分配到各个可用的计算核心上,包括CPU,GPU以及DSP等,提供十分高效的 ...

  9. UIView

    //command+R   运行 //command+.   停止 //command+B   预编译 //command+1.2.3  模拟器大小 //command+shift+h  home键 ...

  10. JVM-操作码助记符

    整理如下,用于以后查找: Opcode Mnemonics Note Constants 0x00 nop 无动作 0x01 aconst_null 把 null 推到操作数栈 0x02 iconst ...