在Linux下编写网络监听程序,比较简单的方法是在超级用户模式下,利用类型为SOCK_PACKET的套接口(用socket()函数创建)来捕获链路帧数据。Linux程序中需引用如下头文件:
#include <sys/socket.h>
#include <sys/ioctl.h> /*ioctl 命令*/
#include <Linux/if_ether.h> /*ethhdr 结构*/
#include <net/if.h> /*ifreq 结构*/
#include <netinet/in.h> /*in_addr结构*/
#include <Linux/ip.h> /*iphdr 结构*/
#include <Linux/udp.h> /*udphdr 结构*/
#include <Linux/tcp.h> /*tcphdr 结构*/
建立SOCK_PACKET类型套接字的方法在11.4.1中已经进行了介绍。如果要监视所有类型的包,则需要采用如下代码:
int fd; /*fd是套接口的描述符*/
fd = socket(AF_INET, SOCK_PACKET, htons(0x0003));
侦听其他主机网络的数据在局域网诊断中经常使用。如果要监听其他网卡的数据,需要将本地的网卡设置为“混杂”模式;当然还需要一个都连接于同一HUB的局域网或者具有“镜像”功能的交换机才可以,否则,只能接收到其他主机的广播包。
char*ethname = "eth0"; /*对网卡eth0进行混杂设置*/
struct ifreq ifr; /*网络接口结构*/
strcpy(ifr.ifr_name, ethname); /*“eth0”写入ifr结构的一个字段中*/
i = ioctl (fd, SIOCGIFFLAGS, &ifr); /*获得eth0的标志位值*/
if (i<0) /*判断是否取出出错*/
{
close(fd);
perror("can’t get flags /n");
return -1;
}
ifr.ifr_flags|=IFF_PROMISC; /*保留原来设置的情况下,在标志位中加入“混杂”方式*/
i = ioctl(fd, SIOCSIFFLAGS, &ifr); /*将标志位设置写入*/
if (i<0) /*判断是否写入出错*/
{
perror("promiscuous set error/n");
return -2;
}
上面的代码使用了ioctl()的SIOCGIFFLAGS和SIOCSIFFLAGS命令,用来取出和写入网络接口的标志设置。注意,在修改网络接口标志的时候,务必要先将之前的标志取出,与想设置的位进行“位或”计算后再写入;不要直接将设置的位值写入,因为直接写入会覆盖之前的设置,造成网络接口混乱。遵循如下的步骤:
(1)取出标志位。
(2)目标标志位=取出的标志位|设置的标志位。
(3)写入目标标志位。