当前位置: 技术问答>linux和unix
奇怪的网络现象__跪求解释
来源: 互联网 发布时间:2015-11-11
本文导语: 各位朋友,我最近编了一个简单的sniffer程序: #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #in...
各位朋友,我最近编了一个简单的sniffer程序:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
struct eth_frame {
unsigned char dst[6];
unsigned char src[6];
unsigned short type;
};//以太网头部
int main()
{
struct sockaddr_in addr;
struct ether_header *peth;
struct iphdr *pip;
struct tcphdr *ptcp;
struct udphdr *pudp;
int sock, r, len;
char *data;
char *ptemp;
char buf[40960];//接收缓存
if((sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_IP))) == -1) //建立socket
{
perror("can not create socket");
exit(1);
}
for(;;)
{
len = sizeof(addr);
r = recvfrom(sock, (char *)buf, sizeof(buf), 0, (struct sockaddr *)&addr, &len);
buf[r] = 0;
ptemp = buf;
peth = (struct ether_header *)ptemp;
ptemp += sizeof(struct ether_header); //指针后移eth头的长度
pip = (struct ip *)ptemp; //pip指向ip层的包头
ptemp += sizeof(struct iphdr);//指针后移ip头的长度
unsigned char *temp = (unsigned char *)malloc(40960);
switch(pip->protocol) //根据不同协议判断指针类型
{
case IPPROTO_TCP:
ptcp = (struct tcphdr *)ptemp; //ptcp指向tcp头部
printf("TCP pkt :FORM:[%s]:[%d] n",inet_ntoa(*(struct in_addr*)&(pip->saddr)),ntohs(ptcp->source));
printf("TCP pkt :TO:[%s]:[%d] n",inet_ntoa(*(struct in_addr*)&(pip->daddr)),ntohs(ptcp->dest));
break;
case IPPROTO_UDP:
pudp = (struct udphdr *)ptemp; //pudp指向udp头部
printf("UDP pkt: len:%d payload len:%d from %s:%d to %s:%d n",
r,
ntohs(pudp->len),
inet_ntoa(*(struct in_addr*)&(pip->saddr)),
ntohs(pudp->source),
inet_ntoa(*(struct in_addr*)&(pip->daddr)),
ntohs(pudp->dest)
);
break;
case IPPROTO_ICMP:
memcpy(temp, buf, r);
printf("From %x:%x:%x:%x:%x:%x to %x:%x:%x:%x:%x:%xn", temp[6], temp[7], temp[8], temp[9], temp[10], temp[11], temp[0], temp[1], temp[2], temp[3], temp[4], temp[5]);//打印"From 源MAC地址 to 目的MAC地址"
printf("ICMP pkt: from %s to %s n",inet_ntoa(*(struct in_addr*)&(pip->saddr)), inet_ntoa(*(struct in_addr*)&(pip->daddr)));//打印"From 源IP地址 to 目的IP地址"
break;
case IPPROTO_IGMP:
printf("IGMP pkt: n");
break;
default:
printf("Unkown pkt, protocl:%d n", pip->protocol);
break;
} //end switch
}//end for
}
本机的IP地址为192.168.0.30,本机网卡MAC地址为00:02:B3:B7:27:FA;
用于测试本机(通过ping命令向本机发送ICMP包文)的另一台主机(以下简称“另机”)的IP地址为192.168.0.27, 网卡MAC地址为00:11:5B:2C:98:86.
现在在本机运行上述程序./sniffer1.o(回车),然后再“另机”上ping 192.168.0.30,下面是本机的现象:
From 0:11:5b:2c:98:86 to 0:2:b3:b7:27:fa
ICMP pkt: from 192.168.0.27 to 192.168.0.27
From 0:11:5b:2c:98:86 to 0:2:b3:b7:27:fa
ICMP pkt: from 192.168.0.27 to 192.168.0.27
...
大家看上面的结果,源MAC和目的MAC地址没有错误,但是为什么源IP和目的IP都是“另机”的IP地址呢?(注意:上面程序对于UDP和TCP包都能够正确的识别出源和目的IP地址,不信你可以试一试)
上面是第一个问题。
现在我将上述程序中的“创建socket”语句修改一下:
从
if((sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_IP))) == -1)
...
改为
if((sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1)
...
其余的地方都不变,在此重复上面的实验,本机的显示结果如下:
From 0:11:5b:2c:98:86 to 0:2:b3:b7:27:fa
ICMP pkt: from 192.168.0.27 to 192.168.0.27
From 0:2:b3:b7:27:fa to 0:11:5b:2c:98:86
ICMP pkt: from 192.168.0.30 to 192.168.0.30
...
即,“另机”每发送一个ICMP包文,本机便显示上述4条结果。大家仔细看一下,其中后两条应该是从本机发回的"ICMP应答"(从源MAC和目的MAC可以看出;而源和目的IP仍然是令我不解的---即我的第一个问题),但是我的网卡没有设置成混杂模式(绝对没有),那为什么将“ETH_P_IP”改为“ETH_P_ALL”之后,就能收到从本机发出去的包文呢(此包文的目的MAC地址并不是本机啊)?
希望高手指教一二,小弟不胜感激啊,先谢谢了!!!!
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
struct eth_frame {
unsigned char dst[6];
unsigned char src[6];
unsigned short type;
};//以太网头部
int main()
{
struct sockaddr_in addr;
struct ether_header *peth;
struct iphdr *pip;
struct tcphdr *ptcp;
struct udphdr *pudp;
int sock, r, len;
char *data;
char *ptemp;
char buf[40960];//接收缓存
if((sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_IP))) == -1) //建立socket
{
perror("can not create socket");
exit(1);
}
for(;;)
{
len = sizeof(addr);
r = recvfrom(sock, (char *)buf, sizeof(buf), 0, (struct sockaddr *)&addr, &len);
buf[r] = 0;
ptemp = buf;
peth = (struct ether_header *)ptemp;
ptemp += sizeof(struct ether_header); //指针后移eth头的长度
pip = (struct ip *)ptemp; //pip指向ip层的包头
ptemp += sizeof(struct iphdr);//指针后移ip头的长度
unsigned char *temp = (unsigned char *)malloc(40960);
switch(pip->protocol) //根据不同协议判断指针类型
{
case IPPROTO_TCP:
ptcp = (struct tcphdr *)ptemp; //ptcp指向tcp头部
printf("TCP pkt :FORM:[%s]:[%d] n",inet_ntoa(*(struct in_addr*)&(pip->saddr)),ntohs(ptcp->source));
printf("TCP pkt :TO:[%s]:[%d] n",inet_ntoa(*(struct in_addr*)&(pip->daddr)),ntohs(ptcp->dest));
break;
case IPPROTO_UDP:
pudp = (struct udphdr *)ptemp; //pudp指向udp头部
printf("UDP pkt: len:%d payload len:%d from %s:%d to %s:%d n",
r,
ntohs(pudp->len),
inet_ntoa(*(struct in_addr*)&(pip->saddr)),
ntohs(pudp->source),
inet_ntoa(*(struct in_addr*)&(pip->daddr)),
ntohs(pudp->dest)
);
break;
case IPPROTO_ICMP:
memcpy(temp, buf, r);
printf("From %x:%x:%x:%x:%x:%x to %x:%x:%x:%x:%x:%xn", temp[6], temp[7], temp[8], temp[9], temp[10], temp[11], temp[0], temp[1], temp[2], temp[3], temp[4], temp[5]);//打印"From 源MAC地址 to 目的MAC地址"
printf("ICMP pkt: from %s to %s n",inet_ntoa(*(struct in_addr*)&(pip->saddr)), inet_ntoa(*(struct in_addr*)&(pip->daddr)));//打印"From 源IP地址 to 目的IP地址"
break;
case IPPROTO_IGMP:
printf("IGMP pkt: n");
break;
default:
printf("Unkown pkt, protocl:%d n", pip->protocol);
break;
} //end switch
}//end for
}
本机的IP地址为192.168.0.30,本机网卡MAC地址为00:02:B3:B7:27:FA;
用于测试本机(通过ping命令向本机发送ICMP包文)的另一台主机(以下简称“另机”)的IP地址为192.168.0.27, 网卡MAC地址为00:11:5B:2C:98:86.
现在在本机运行上述程序./sniffer1.o(回车),然后再“另机”上ping 192.168.0.30,下面是本机的现象:
From 0:11:5b:2c:98:86 to 0:2:b3:b7:27:fa
ICMP pkt: from 192.168.0.27 to 192.168.0.27
From 0:11:5b:2c:98:86 to 0:2:b3:b7:27:fa
ICMP pkt: from 192.168.0.27 to 192.168.0.27
...
大家看上面的结果,源MAC和目的MAC地址没有错误,但是为什么源IP和目的IP都是“另机”的IP地址呢?(注意:上面程序对于UDP和TCP包都能够正确的识别出源和目的IP地址,不信你可以试一试)
上面是第一个问题。
现在我将上述程序中的“创建socket”语句修改一下:
从
if((sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_IP))) == -1)
...
改为
if((sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1)
...
其余的地方都不变,在此重复上面的实验,本机的显示结果如下:
From 0:11:5b:2c:98:86 to 0:2:b3:b7:27:fa
ICMP pkt: from 192.168.0.27 to 192.168.0.27
From 0:2:b3:b7:27:fa to 0:11:5b:2c:98:86
ICMP pkt: from 192.168.0.30 to 192.168.0.30
...
即,“另机”每发送一个ICMP包文,本机便显示上述4条结果。大家仔细看一下,其中后两条应该是从本机发回的"ICMP应答"(从源MAC和目的MAC可以看出;而源和目的IP仍然是令我不解的---即我的第一个问题),但是我的网卡没有设置成混杂模式(绝对没有),那为什么将“ETH_P_IP”改为“ETH_P_ALL”之后,就能收到从本机发出去的包文呢(此包文的目的MAC地址并不是本机啊)?
希望高手指教一二,小弟不胜感激啊,先谢谢了!!!!
|
问题一:inet_ntoa不可重入,要把其内容拷贝出来,否则你的代码显示什么结果与编译器处理有关。
问题二:这不是混杂模式的结果。ETH_P_ALL就是anything。
问题二:这不是混杂模式的结果。ETH_P_ALL就是anything。
|
楼上提醒我了,记得以前我也犯过这个错误……
inet_ntoa返回的指针是指向一个static的地址空间的,相当与一个全局变量,后一次调用将覆盖前一次的内容。
当年我还以为是malloc出来的,试图去释放它……
inet_ntoa返回的指针是指向一个static的地址空间的,相当与一个全局变量,后一次调用将覆盖前一次的内容。
当年我还以为是malloc出来的,试图去释放它……