免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 6650 | 回复: 17
打印 上一主题 下一主题

SOCK_RAW 监听不到数据包 ?有代码 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-07-30 20:19 |只看该作者 |倒序浏览

  1. #include "stdio.h"
  2. #include "stdlib.h"
  3. #include "string.h"

  4. #include "unistd.h"
  5. #include "signal.h"
  6. #include "sys/socket.h"
  7. #include "sys/types.h"
  8. #include "netinet/in.h"
  9. #include "arpa/inet.h"
  10. #include "errno.h"
  11. #include "netdb.h"
  12. #include "net/if.h"
  13. #include "sys/ioctl.h"
  14. #include "linux/if_ether.h"

  15. extern int errno;

  16. void catch_sigint(int signum) {
  17.         printf("catch sigint...\n");
  18.         exit(0);
  19. }


  20. int main() {

  21.         int sockfd;
  22.         if((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) {
  23.                  perror("socket()");
  24.                  return(-1);
  25.         }


  26.         struct sigaction sig;
  27.         sig.sa_handler = catch_sigint;
  28.         sigemptyset(&sig.sa_mask);
  29.         sig.sa_flags = 0;
  30.         if(sigaction(SIGINT, &sig, 0) == -1)perror("sigaction()");


  31.         char buf[2048];
  32.         char strs[128];
  33.         char strd[128];
  34.         for(;;) {
  35.                 int n = recvfrom(sockfd, buf, sizeof(buf), 0,0, 0);
  36.                 if(n == -1)perror("recvfrom()");
  37.                 else  {
  38.                         printf("success recv %d bytes\n", n);
  39.                         continue;
  40.                 }
  41.         }
  42.         return 0;
  43. }                                    
复制代码


有数据流过但是监听不到!!!
哪里出问题了呢,还是本身就是应该监听不到呢!
要是换成 socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)) 就能收到所有数据帧的
什么原因呢?

[ 本帖最后由 HJLin 于 2008-7-30 21:11 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2008-07-30 21:09 |只看该作者
我觉得网卡收到一个数据帧的时候,执行以太网输入例程, ip输入例程, 然后在进入应用层输入例程之前,会首先根据ip包的协议类型检查系统中是否有通过socket(AF_INET, SOCK_RAW, ..)创建并且协议类型匹配的文件描述字.如果有的话就拷贝一份ip包到每个符合条件的文件描述字的缓冲区.然后就会继续进入系统的应用层输入例程.

所以,我觉得理论上是应该能够收到的啊,有大牛帮忙分析一下吗?

[ 本帖最后由 HJLin 于 2008-7-30 21:21 编辑 ]

论坛徽章:
0
3 [报告]
发表于 2008-07-30 21:19 |只看该作者
:em12: :em12: :em12:
In article
<4ae0-bf5d-490399235...@d77g2000hsb.googlegroups.com[/email][/email]>,


lak <lakindi...@gmail.com> wrote:
> On Jul 17, 6:57 am, Barry Margolin <bar...@alum.mit.edu> wrote:
> > In article
> > <4aa0-9f03-38161e271...@b1g2000hsg.googlegroups.com[/email][/email]>,

> >  lak <lakindi...@gmail.com> wrote:
> > >  Receiving of all IP protocols via IPPROTO_RAW is not possible using
> > > raw sockets. Why?


> > Because some protocols, such as TCP and UDP, are handled automatically
> > by the network stack.  When the stack receives a TCP or UDP packet with
> > a destination port that isn't open, it will send an error response back
> > to the sender.


> Can you please explain a little more? please.



You use a raw socket to send out a TCP SYN packet with source port 5000
and destination port 80.  The web server sends back a SYN-ACK with
source port 80 and destination port 5000.  Since this is a TCP packet
the kernel passes it to the TCP driver.  The TCP driver searches its
connection table looking for one with a local port 5000 and remote port
80.  It can't find one, so it sends a RST packet, and this causes the
server to abort the connection.

so please try
  1. socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP))
复制代码

to receive all ip packets
and use
  1. socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))
复制代码

to receive all packets including arp, rarp and ip

[ 本帖最后由 duanjigang 于 2008-7-30 21:21 编辑 ]

论坛徽章:
0
4 [报告]
发表于 2008-07-30 21:28 |只看该作者
我发现问题了啊!不过还是感谢你的回答
创建socket的时候
socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
都可以用
socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
这个就是没有用

莫非只能接收具体的协议的数据包,我晕了啊!
就不能像 socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))一样啊,可以接收所有类型的数据帧吗??

还是继续的困惑着....我也是看的网上的说要用IPPROTO_RAW的啊,它的值是255,应该是接收所有协议类型的意思啊...

继续困惑着


另外我现在谈的是AF_INET协议簇的,PF_PACKET协议簇的我已经看过了...知道了

[ 本帖最后由 HJLin 于 2008-7-30 21:32 编辑 ]

论坛徽章:
0
5 [报告]
发表于 2008-07-30 21:28 |只看该作者

论坛徽章:
0
6 [报告]
发表于 2008-07-30 21:35 |只看该作者
原帖由 duanjigang 于 2008-7-30 21:28 发表
再参考这篇:
http://bbs.chinaunix.net/viewthr ... &extra=page%3D1


我上面还有问题啊,帮我看看吗?

论坛徽章:
0
7 [报告]
发表于 2008-07-30 21:58 |只看该作者
莫非只能接收具体的协议的数据包,我晕了啊!
就不能像 socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))一样啊,可以接收所有类型的数据帧吗??


(1):对于UDP/TCP产生的IP数据包,内核不将它传递给任何原始套接字,而只是将这些数据交给对应的UDP/TCP数据处理句柄(所以,如果你想要通过原始套接字来访问TCP/UDP或者其它类型的数据,调用socket函数创建原始套接字第三个参数应该指定为htons(ETH_P_IP),也就是通过直接访问数据链路层来实现.

(2):对于ICMP和EGP等使用IP数据包承载数据但又在传输层之下的协议类型的IP数据包,内核不管是否已经有注册了的句柄来处理这些数据,都会将这些IP数据包复制一份传递给协议类型匹配的原始套接字.

[ 本帖最后由 duanjigang 于 2008-7-30 22:02 编辑 ]

论坛徽章:
0
8 [报告]
发表于 2008-07-30 22:05 |只看该作者
另外我现在谈的是AF_INET协议簇的,PF_PACKET协议簇的我已经看过了
Well, let me start off by saying that AF_* is exactly the same as PF_*... Ie: AF_INET
is the same as PF_INET, AF_PACKET == PF_PACKET, etc... The AF/PF dichotomy
came about due to some misguided attempt early in the formation of the sockets
API to allow for a protocol to host multiple different address types... But, such a
thing never came about, and in practice there's absolutely no difference between
AF_* and PF_*, and people use them interchangably... (Though, technically, as I'm
sure Michael will mention, you're supposed to use PF_* as socket()'s first arg, and
AF_* as the *_family value in sockaddr_* structs... But, I say screw that, and just use
AF_* everywhere... ;-) Here is an old message on Richard Stevens' old home page
http://www.kohala.com/start/lanciani.96apr10.txt),
which goes into more detail on the original reason for the split, and why AF_* is
the only logical choice to use these days... *ducks Michael's wrath* ;-))

Now, as for AF_INET vs. AF_PACKET, well the former is the normal IP family, in
which you can have TCP, UDP, or raw sockets, while the latter is the Linux-specific
packet family, specifically designed for sniffing link-level packets off the wire... Ie:
with an AF_PACKET socket, you can sniff not only IP traffic, but anything else as
well... And, you can get at the link-level (eg: Ethernet) headers, as well... See
"man 7 packet" and "man 7 raw" for the difference between AF_INET/SOCK_RAW
and AF_PACKET/SOCK_{RAW,DGRAM}...

[ 本帖最后由 duanjigang 于 2008-7-30 22:09 编辑 ]

论坛徽章:
0
9 [报告]
发表于 2008-07-30 22:09 |只看该作者
原帖由 duanjigang 于 2008-7-30 21:58 发表
莫非只能接收具体的协议的数据包,我晕了啊!
就不能像 socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))一样啊,可以接收所有类型的数据帧吗??

(1):对于UDP/TCP产生的IP数据包,内核不将它传递给任何原始套接字 ...


下面的代码,能够使用,还是哪里我理解的有问题...

  1. #include "stdio.h"
  2. #include "stdlib.h"
  3. #include "string.h"

  4. #include "unistd.h"
  5. #include "signal.h"
  6. #include "sys/socket.h"
  7. #include "sys/types.h"
  8. #include "netinet/in.h"
  9. #include "arpa/inet.h"
  10. #include "errno.h"
  11. #include "netdb.h"
  12. #include "net/if.h"
  13. #include "sys/ioctl.h"
  14. #include "linux/if_ether.h"

  15. extern int errno;

  16. void catch_sigint(int signum) {
  17.         printf("catch sigint...\n");
  18.         exit(0);
  19. }


  20. int main() {
  21.         int sockfd;
  22.         if((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) {
  23.                  perror("socket()");
  24.                  return(-1);
  25.         }

  26.         struct sigaction sig;
  27.         sig.sa_handler = catch_sigint;
  28.         sigemptyset(&sig.sa_mask);
  29.         sig.sa_flags = 0;
  30.         if(sigaction(SIGINT, &sig, 0) == -1)perror("sigaction()");


  31.         char buf[2048];
  32.         for(;;) {
  33.                 int n = recvfrom(sockfd, buf, sizeof(buf), 0,0, 0);
  34.                 if(n == -1)perror("recvfrom()");
  35.                 else  {
  36.                         printf("success recv %d bytes\n", n);
  37.                         char* tcp = buf+20;
  38.                         //tcp analyse code...
  39.                 }
  40.         }
  41.         return 0;
  42. }
复制代码

论坛徽章:
0
10 [报告]
发表于 2008-07-30 22:51 |只看该作者
原帖由 HJLin 于 2008-7-30 22:09 发表


下面的代码,能够使用,还是哪里我理解的有问题...

#include "stdio.h"
#include "stdlib.h"
#include "string.h"

#include "unistd.h"
#include "signal.h"
#include "sys/socket.h"
#include " ...

这就是AF_INET和AF_PACKET的区别了
使用AF_INET,就跟普通socekt一样,你能通过第三个参数来制定处理TCP,UDP或者ICMP等包
而使用AF_PACKET第三个参数指定为IPPROTO_TCP,IPPROTO_UDP, IPPROTO_ICMP等就收不到数据包,因为上文中已提到:
“as for AF_INET vs. AF_PACKET, well the former is the normal IP family, in
which you can have TCP, UDP, or raw sockets, while the latter is the Linux-specific
packet family, specifically designed for sniffing link-level packets off the wire”

AF_PACKET是专门用来处理raw socket的,符合我上面列举的规则
是否可以这样总结raw socket的用法:
(1):如果想单独处理TCP,UDP或者ICMP,可用AF_INET, 第三个参数用IPPROTO_TCP, IPPROTO_UDP等
(2):如果想对各种IP包进行处理,则用AF_PACKET/PF_PACKET,第三个参数用htons(ETH_P_IP)
(3):如果想处理一切链路层上的包(IP,RARP,ARP等),则用AF_PACKET/PF_PACKET,第三个参数用 htons(ETH_P_ALL)


[ 本帖最后由 duanjigang 于 2008-7-30 23:04 编辑 ]
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP