(十三)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;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM