zoukankan      html  css  js  c++  java
  • (十三)Packet socket 和 sockaddr_ll

    描述
            本文简单描述了数据链路层的socket使用的两种方法
    正文
         Linux下有两种方式接收数据链路层的数据包:
        (1)原始的方法,即创建一个类型为SOCK_PACKET的socket,该方法很普遍,但是缺乏灵活性;
        (2)最新的方法,引入了帧过滤功能和性能上的提升,即创建一个指定协议簇为 PF_PACKET的socket,这需要root权限(类似于创建一个raw socket),并且socket的第三个参数必须指定一个以太网帧类型(Ethernet frame type);
            使用第二种方法时,socket的第二个参数可以被设置为SOCK_DGRAM,主要区别是当指定SOCK_DGRAM时,获取的数据包是去掉了数据链路层的头(link-layer header),当指定SOCK_RAW时,获取的数据包是一个完整的数据链路层数据包; SOCK_PACKET只返返回完整的数据链路层数据包,示例,接收完整的数据链路层数据包,可以这样写:

    1. fd = socket(AF_INET, SOCK_PACKET, htons(ETH_P_ALL)); /* older systems */

    或者

    1. fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); /* newer systems */

    这样将会接收到数据链路层所有协议帧;
    如果我们只需要IPv4帧,可以这样写:

    1. fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP)); /* new systems */

    或者

    1. fd = socket(AF_INET, SOCK_PACKET, htons(ETH_P_IP)); /* older systems */

            其它数据链路层类型定义的常量参数有 ETH_P_ARP 和 ETH_P_IPV6;
            指定协议(protocol)为ETH_P_XXX即告诉数据链路层我只接收该类型的帧(frame),socket会自动过滤。如果数据链路支持混杂模式(promiscuous mode),可以设置socket可选参数PACKET_ADD_MEMBERSHIP选项,使用packet_mreq结构体指定一个以太网接口和混杂模式行为(PACKET_MR_PROMISC)。

            接下来详解 数据链路层的头信息结构体 sockaddr_ll 

    点击(此处)折叠或打开        

    1. #include <sys/socket.h>
    2.        #include <linux/if_packet.h>
    3.        #include <net/ethernet.h> /* the L2 protocols */
    4.        packet_socket = socket(AF_PACKET, int socket_type, int protocol);

            数据链路层的头信息通常定义在 sockaddr_ll 的结构体中,protocol是按照网络字节顺序(network byte order),大部分定义在头文件中,设置协议时,例如 htons(ETH_P_ALL)来接收所有的数据包;
            如果要获取从指定以太网接口卡上的数据包时,在 struct sockaddr_ll中指定网络接口卡,绑定(bind)数据包到该interface上。只有sll_protocol和 sll_ifindex这两个地址字段是用来bind的。
            

    1. struct sockaddr_ll {
    2.                unsigned short sll_family; /* Always AF_PACKET */
    3.                unsigned short sll_protocol; /* Physical-layer protocol */
    4.                int sll_ifindex; /* Interface number */
    5.                unsigned short sll_hatype; /* ARP hardware type */
    6.                unsigned char sll_pkttype; /* Packet type */
    7.                unsigned char sll_halen; /* Length of address */
    8.                unsigned char sll_addr[8]; /* Physical-layer address */
    9.            };

             sll_protocol : 标准以太网协议类型,按网络字节顺序。定义在中。
             sll_ifindex: interface索引,0 匹配所有的网络接口卡; 
             sll_hatype: ARP 硬件地址类型(hardware address type) 定义在中,常用 ARPHRD_ETHER
             sll_pkttype: 包含了packet类型。
                     PACK_HOST                  包地址为本地主机地址。
                     PACK_BROADCAST    物理层广播包。
                     PACK_MULTICAST      发送到物理层多播地址的包。
                     PACK_OTHERHOST    发往其它在混杂模式下被设备捕获的主机的包。
                     PACK_OUTGOING        本地回环包;
             sll_addr 和 ssl_halen 包含了物理层地址和其长度;

            当发送数据包时,指定 sll_family, sll_addr, sll_halen, sll_ifindex, sll_protocol 就足够了。其它字段设置为0; sll_hatype和 sll_pkttype是在接收数据包时使用的; 如果要bind, 只需要使用 sll_protocol和 sll_ifindex;

  • 相关阅读:
    缓存读写策略
    支撑京东小程序的开发框架 「Taro」
    Zookeeper vs Etcd
    前端开发利器 Web Replay
    kafka 中 zookeeper 具体是做什么的?
    newSQL 到底是什么?
    zookeeper配置集群
    zookeeper配置文件说明
    ssh远程访问-提示密钥不安全
    Nodejs-log4js使用配置
  • 原文地址:https://www.cnblogs.com/zhangshenghui/p/6097492.html
Copyright © 2011-2022 走看看