打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
linux sock
sock_raw原始套接字编程可以接收到本机网卡上的数据帧或者数据包,对与监听网络的流量和分析是很有作用的.一共可以有3种方式创建这种 socket
1.socket(AF_INET, SOCK_RAW, IPPROTO_TCP|IPPROTO_UDP|IPPROTO_ICMP)发送接收ip数据包
2.socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL))发送接收以太网数据帧
3.socket(AF_INET, SOCK_PACKET, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL))过时了,不要用啊
理解一下SOCK_RAW的原理, 比如网卡收到了一个 14+20+8+100+4 的udp的以太网数据帧.
首先,网卡对该数据帧进行硬过滤(根据网卡的模式不同会有不同的动作,如果设置了promisc混杂模式的话,则不做任何过滤直接交给下一层输 入例程,否则非本机mac或者广播mac会被直接丢弃).按照上面的例子,如果成功的话,会进入ip输入例程.但是在进入ip输入例程之前,系统会检查系 统中是否有通过socket(PF_PACKET, SOCK_RAW, ..)创建的套接字.如果有的话并且协议相符,在这个例子中就是需要ETH_P_IP或者ETH_P_ALL类型.系统就给每个这样的socket接收缓 冲区发送一个数据帧拷贝.然后进入下一步.
其次,进入了ip输入例程(ip层会对该数据包进行软过滤,就是检查校验或者丢弃非本机ip或者广播ip的数据包等,具体要参考源代码),例子 中就是如果成功的话会进入udp输入例程.但是在交给udp输入例程之前,系统会检查系统中是否有通过socket(AF_INET, SOCK_RAW, ..)创建的套接字.如果有的话并且协议相符,在这个例子中就是需要IPPROTO_UDP类型.系统就给每个这样的socket接收缓冲区发送一个数据 帧拷贝.然后进入下一步.
最后,进入udp输入例程 ...
ps:如果校验和出错的话,内核会直接丢弃该数据包的.而不会拷贝给sock_raw的套接字,因为校验和都出错了,数据肯定有问题的包括所有信息都没有意义了.
进一步分析他们的能力.
1. socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
能:该套接字可以接收协议类型为(tcp udp icmp等)发往本机的ip数据包,从上面看的就是20+8+100.
不能:不能收到非发往本地ip的数据包(ip软过滤会丢弃这些不是发往本机ip的数据包).
不能:不能收到从本机发送出去的数据包.
发送的话需要自己组织tcp udp icmp等头部.可以setsockopt来自己包装ip头部
这种套接字用来写个ping程序比较适合
     
2. socket(PF_PACKET, SOCK_RAW, htons(x));
这个套接字比较强大,创建这种套接字可以监听网卡上的所有数据帧.从上面看就是20+20+8+100.最后一个以太网crc从来都不算进来 的,因为内核已经判断过了,对程序来说没有任何意义了.
能: 接收发往本地mac的数据帧
能: 接收从本机发送出去的数据帧(第3个参数需要设置为ETH_P_ALL)
能: 接收非发往本地mac的数据帧(网卡需要设置为promisc混杂模式)
协议类型一共有四个
ETH_P_IP 0x800      只接收发往本机mac的ip类型的数据帧
ETH_P_ARP 0x806      只接受发往本机mac的arp类型的数据帧
ETH_P_RARP 0x8035     只接受发往本机mac的rarp类型的数据帧
ETH_P_ALL 0x3         接收发往本机mac的所有类型ip arp rarp的数据帧, 接收从本机发出的所有类型的数据帧.(混杂模式打开的情况下,会接收到非发往本地mac的数据帧)
发送的时候需要自己组织整个以太网数据帧.所有相关的地址使用struct sockaddr_ll 而不是struct sockaddr_in(因为协议簇是PF_PACKET不是AF_INET了),比如发送给某个机器,对方的地址需要使用struct sockaddr_ll.
这种socket大小通吃,强悍
下面是一段相关的代码:

     ...
    int
sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    struct sockaddr_ll sll;
     memset( & sll, 0, sizeof(sll) );
     sll.sll_family = PF_PACKET;
    struct ifreq ifstruct;
   strcpy(ifstruct.ifr_name, "eth0");
   ioctl(sockfd, SIOCGIFINDEX, &ifstruct);
    sll.sll_ifindex = ifstruct.ifr_ifindex;
     sll.sll_protocol = htons(ETH_P_ALL);
    if(bind(fd, (struct sockaddr *) &sll, sizeof(sll)) == -1 ) {
       perror("bind()");
    ...

int set_promisc(char *interface, int fd) {
        struct ifreq ifr;
         strcpy(ifr.ifr_name, interface);
        if(ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) {
                 perror("iotcl()");
                 return -1;
         }
         ifr.ifr_flags |= IFF_PROMISC;
        if(ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) {
                 perror("iotcl()");
                 return -1;
         }
         return 0;
}

int unset_promisc(char *interface, int fd) {
        struct ifreq ifr;
         strcpy(ifr.ifr_name, interface);
        if(ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) {
                 perror("iotcl()");
                 return -1;
         }
         ifr.ifr_flags &= ~IFF_PROMISC;
        if(ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) {
                 perror("iotcl()");
                 return -1;
         }
         return 0;
}

3. socket(AF_INET, SOCK_PACKET, htons(ETH_P_ALL))这个最好不要用,反正我不用...
总结使用方法: 1.只想收到发往本机某种协议的ip数据包的话用第一种就足够了
            2. 更多的详细的内容请使用第二种.包括ETH_P_ALL参数和混杂模式都可以使它的能力不断的加强.
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
linux sock_raw原始套接字编程
利用原始套接字抓取数据
【Linux网络编程】原始套接字编程
socket修改本机IP
TCP、UDP、ICMP的一些疑问的解答
Linux虚拟网络设备之tun/tap
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服