linux socket 操作鏈結路層

來源:互聯網
上載者:User

   Linux提供最常用的網路通訊應用程式開發介面--Berkerley通訊端(Socket).它既適用於同一主機上處理序間通訊(IPC),又適用於不同主機上的處理序間通訊。通訊端的設定通過socket調用完成:

int socket(int family,int type,int protocol);

其中family指通訊域或協議族,Linux系統支援的網路通訊協定族有PF_UNIX,PF_IPX,PF_PACKET等幾十種;type為通訊端類型, 目前有SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET等;protocol是通訊端所用的特定協議類型號.

Linux 系統提供的基於資料連結層開發應用程式的介面整合在通訊端中,它是通過建立packet類型的套接宇.使應用程式可直接在資料連結層接收或發送未被系統處理的原始的資料報文(如ARP報文),使用者也可以使用packet類型的套接宇在物理層上定義自己特殊的網路通訊協定。只有註冊號為0的使用者(超級使用者)進程才能建立或開啟用於訪問網路低層的通訊端.在Linux系統中,用以下三種方式建立的packet通訊端可直接用於訪問資料連結層:
(1)PF_INET協議族中SOCK_PACKEI類型的通訊端
(2)PF_PACKET協議族中SOCK_RAW類型的通訊端
(3)PF_PACKET協議族中SOCK_DGRAM類型的通訊端

Linux 2.0中對資料連結層的操作主要使用SOCK_PACKET定義的packet通訊端.初始化定義如下:
sockfd=socket(AF_INET,SOCK_PACKET,protocol);
其中,protocol用於決定通訊端所使用的物理層協議(在IEEE802.3中定義).筆者在此選擇常用的物理層協議ETH_P_IP(Internet協議).SOCK_PACKET使用一種比較老的sockaddr_pkt資料結構來設定網路介面。

在Linux 2 2中使用PF_PACKET代替SOCK_PACKET來定義packet通訊端.這種通訊端的初始化定義如下:
sockfd=socket(PF_PACKET,socket_type,protocol);
其中socket_type只能為SOCK_RAW或SOCK_DGRAM,protocol為物理層通訊協定(同上)。SOCK_RAW和 SOCK_DGRAM類型通訊端使用一種與裝置無關的標準物理層地址結構sockaddr_ll,但具體操作的報文格式不同。SOCK_RAW通訊端直接向網路硬體驅動程式發送(或從網路硬體驅動程式接收)沒有任何處理的完整資料報文(包括物理幀的幀頭),這就要求程式員必須瞭解對應裝置的物理幀幀頭結構,才能正確地裝載和分析報文。SOCK_DGRAM通訊端收到的資料報文的物理幀幀頭會被系統自動去掉,同樣,在發送時.系統將會根據
sockaddr_ll結構中的目的地址資訊為資料報文舔加一個台適的物理幀幀頭。

預設情況下.從任何介面收到的符合指定協議的所有資料報文都會被傳送到packet通訊端。使用bind系統調用以一個sochddr_l1地址結構將paccket通訊端與某個網路介面相綁定,可使通訊端只接收指定介面的
資料報文.socaddr_ll地址結構定義如下:
struct sockaddr_ll
{
unsigned short sll_family; /* 總是 AF_PACKET */
unsigned short sll_protocol; /* 物理層的協議 */
int sll_ifindex; /* 介面號 */
unsigned short sll_hatype; /* 前序類型 */
unsigned char sll_pkttype; /* 分組類型 */
unsigned char sll_halen; /* 地址長度 */
unsigned char sll_addr[8]; /* 物理層地址 */
};

一、利用PF_lNET協議族中SOCK_PACKET類型的套接宇實現ARP
(1)建通訊端
建立套接宇採用socket系統調用,格式如下:
sockfd=socket(PF_INET,SOCK_PACKET,htons(ETH_P_ARP));
(2)裝載報文
對於SOCK_PACKET類型的通訊端,乙太網路物理幀頭應作為所發送報文一部分由程式員設定,物理幀頭的格式定義如下:(in /usr/include/linux/if_ether.h)
92 struct ethhdr
93 {
94 unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
95 unsigned char h_source[ETH_ALEN]; /* source ether addr */
96 unsigned short h_proto; /* packet type ID field */
97 };
實際發送的位址解析報文幀由乙太網路物理幀頭與幀資料(ARP報文)共同組成,用結構體ARPPACKET表
示如下:
typedef struct {
struct ethhdr eth_header; //struct defined in linux/if_ether.h
ARPHDR arp_header;
}ARPPACKET;
上述報文結構的裝載比較簡單。對ARP部分,arp_header的設定如下:
ptk.arp_header.ar_hrd=htons(ARPHRD_ETHER); //ARPHRD_ETHER is defined in linux/if_arp.h
ptk.arp_header.ar_pro=htons(ETHERTYPE_IP);
ptk.arp_header.ar_hln=6;
ptk.arp_header.ar_pln=4;
ptk.arp_header.ar_op=htons(ARPOP_REQUEST);

pkt.arp_header.ar_sha[]、 pkt.arp_header.ar_sip[]、pkt_arp_header.ar_tip[]分別填入原生物理地址、ip地址和要解析的對方主機的ip地址.返回報文中pkt.arp_header.tha[]中的內容就是解析
得到的對方主機的物理地址。

對於乙太網路幀頭部分,pkt.eth_header.h_dest[]為目的地址,即廣播物理地址0xFFFFFF, pkt.eth_header.source[]為本機物理地址(同pkt.arp_header.ar_sha[]),
pkt.eth_header.h_proto賦值htons(ETHERTYPE_ARP)表示為位址解析類型報文。
ETHERTYPE_ARP與ETH_P_ARP的值都是0x0806,只是定義的檔案不同。前者定義在net/ethernet.h,後者定義在linux/if_ether.h

(3)報文的發送與接收
在資料連結層發送/接收報文與在IP層發送/接收資料報文類似,分別用系統調用sendto()和recvfrom()
完成,只是要將配置好的含有目標地址的報文發往本網硬體而不是目標主機。相應的程式段如下:
struct sockaddr to,from;
int fromlen=0;
strcpy(to.sa_data,"eth0");
sendto(sockfd,pkt,sizeof(struct ARPPACKET),0,&to,sizeof(struct sockaddr));
recvfrom(sockfd,buf,PACKET_SIZE,0,&from,&fromlen);
其中buf為包含結構體ARPPACKET的字元型指標。

通過檢驗所接收到的ARP應答報文中arp_header.ar_op項是否為ARPOP_REPLY(ARP應答)同時arp_header.ar_tip是否為已知的對方主機的IP地址來判斷所得到的解析地址是否正確.

二、利用PF_PACKET協議族中SOCK_RAW類型的通訊端實現ARP
(1)建立通訊端
sockfd=socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ARP));
(2)裝載報文
與SOCK_PACKET類型的通訊端相同,SOCK_RAW類型的通訊端對鏈路層操作時,也要求乙太網路物理幀頭應作為所發送報文一部分由程式員設定.
(3)報文的發送與接收
SOCK_RAW類型通訊端使用標準的物理層地址結構sockaddr_ll,所以,報文發送之前,應將通訊端綁定到(使用bind()系統調用)配置好的本地物理地址結構my_etheraddr,同時還需配置目的物理地址結構broad_etheraddr.
樣本如下:
struct aockaddr_ll my_etheraddr,broad_etheraddr;
my_etheraddr.sll_family=AF_PACKET;
my_etheraddr.sll_protocol=htons(ETH_P_ARP);
my_etheraddr.sll_ifindex=2; /*介面號2表示是eth0*/
my_etheraddr.sll_hatype=ARPHRD_ETHER;
my_etheraddr.sll_pkttype=PACKET_HOST;
my_etheraddr.sll_halen=ETH_ALEN;
my_etheraddr.sll_addr[8]中放入本主機的物理地址。

broad_etheraddr的配置除了sll_pkttype取PACKET_BROADCAST和sll_addr取廣播物理地址(0xFFFFFF)外,其他選項與my_etheraddr配置相同。

綁定格式如下:
bind(sockfd,(struct sockaddr *)&my_etheraddr,sizeof(my_etheraddr));

發送與接收調用程式如下:
sendto(sockfd,buf,sizeof(struct ARPPACKET),0,
(struct sockaddr *)&broad_etheraddr,sizeof(broad_etheraddr));

recvform(sockfd,buf,PACKET_SIZE,&from,&fromlen);

三、利用PF_PACKET協議族中SOCK_DGRAM類型的通訊端實現ARP
SOCK_DGRAM類型的通訊端不要求程式員配置乙太網路幀頭,所以所發送的報文只有資料區(ARP報文)部分,其它與SOCK_RAW類型的通訊端相同。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.