日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux sock_raw原始套接字编程

發(fā)布時(shí)間:2023/12/10 linux 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux sock_raw原始套接字编程 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
sock_raw原始套接字編程可以接收到本機(jī)網(wǎng)卡上的數(shù)據(jù)幀或者數(shù)據(jù)包,對(duì)與監(jiān)聽網(wǎng)絡(luò)的流量和分析是很有作用的.一共可以有3種方式創(chuàng)建這種socket
?
1.socket(AF_INET, SOCK_RAW, IPPROTO_TCP|IPPROTO_UDP|IPPROTO_ICMP)發(fā)送接收ip數(shù)據(jù)包
2.socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL))發(fā)送接收以太網(wǎng)數(shù)據(jù)幀
3.socket(AF_INET, SOCK_PACKET, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL))過時(shí)了,不要用啊
?
理解一下SOCK_RAW的原理, 比如網(wǎng)卡收到了一個(gè) 14+20+8+100+4 的udp的以太網(wǎng)數(shù)據(jù)幀.
?
首 先,網(wǎng)卡對(duì)該數(shù)據(jù)幀進(jìn)行硬過濾(根據(jù)網(wǎng)卡的模式不同會(huì)有不同的動(dòng)作,如果設(shè)置了promisc混雜模式的話,則不做任何過濾直接交給下一層輸 入例程,否則非本機(jī)mac或者廣播mac會(huì)被直接丟棄).按照上面的例子,如果成功的話,會(huì)進(jìn)入ip輸入例程.但是在進(jìn)入ip輸入例程之前,系統(tǒng)會(huì)檢查系 統(tǒng)中是否有通過socket(AF_PACKET, SOCK_RAW, ..)創(chuàng)建的套接字.如果有的話并且協(xié)議相符,在這個(gè)例子中就是需要ETH_P_IP或者ETH_P_ALL類型.系統(tǒng)就給每個(gè)這樣的socket接收緩 沖區(qū)發(fā)送一個(gè)數(shù)據(jù)幀拷貝.然后進(jìn)入下一步.
?
其次,進(jìn)入了ip輸入例程(ip層會(huì)對(duì)該數(shù)據(jù)包進(jìn)行軟過濾,就是檢查校驗(yàn)或者丟棄非本機(jī)ip 或者廣播ip的數(shù)據(jù)包等,具體要參考源代碼),例子 中就是如果成功的話會(huì)進(jìn)入udp輸入例程.但是在交給udp輸入例程之前,系統(tǒng)會(huì)檢查系統(tǒng)中是否有通過socket(AF_INET, SOCK_RAW, ..)創(chuàng)建的套接字.如果有的話并且協(xié)議相符,在這個(gè)例子中就是需要IPPROTO_UDP類型.系統(tǒng)就給每個(gè)這樣的socket接收緩沖區(qū)發(fā)送一個(gè)數(shù)據(jù) 幀拷貝.然后進(jìn)入下一步.
?
最后,進(jìn)入udp輸入例程 ...
?
ps:如果校驗(yàn)和出錯(cuò)的話,內(nèi)核會(huì)直接丟棄該數(shù)據(jù)包的.而不會(huì)拷貝給sock_raw的套接字,因?yàn)樾r?yàn)和都出錯(cuò)了,數(shù)據(jù)肯定有問題的包括所有信息都沒有意義了.
?
進(jìn)一步分析他們的能力.
1. socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
能:該套接字可以接收協(xié)議類型為(tcp udp icmp等)發(fā)往本機(jī)的ip數(shù)據(jù)包,從上面看的就是20+8+100.
不能:不能收到非發(fā)往本地ip的數(shù)據(jù)包(ip軟過濾會(huì)丟棄這些不是發(fā)往本機(jī)ip的數(shù)據(jù)包).
不能:不能收到從本機(jī)發(fā)送出去的數(shù)據(jù)包.
發(fā)送的話需要自己組織tcp udp icmp等頭部.可以setsockopt來自己包裝ip頭部
這種套接字用來寫個(gè)ping程序比較適合
????
2. socket(PF_PACKET, SOCK_RAW, htons(x));?
這個(gè)套接字比較強(qiáng)大,創(chuàng)建這種套接字可以監(jiān)聽網(wǎng)卡上的所有數(shù)據(jù)幀.從上面看就是20+20+8+100.最后一個(gè)以太網(wǎng)crc從來都不算進(jìn)來的,因?yàn)閮?nèi)核已經(jīng)判斷過了,對(duì)程序來說沒有任何意義了.
能: 接收發(fā)往本地mac的數(shù)據(jù)幀
能: 接收從本機(jī)發(fā)送出去的數(shù)據(jù)幀(第3個(gè)參數(shù)需要設(shè)置為ETH_P_ALL)
能: 接收非發(fā)往本地mac的數(shù)據(jù)幀(網(wǎng)卡需要設(shè)置為promisc混雜模式)
協(xié)議類型一共有四個(gè)
ETH_P_IP? 0x800????? 只接收發(fā)往本機(jī)mac的ip類型的數(shù)據(jù)幀
ETH_P_ARP 0x806????? 只接受發(fā)往本機(jī)mac的arp類型的數(shù)據(jù)幀
ETH_P_ARP 0x8035???? 只接受發(fā)往本機(jī)mac的rarp類型的數(shù)據(jù)幀
ETH_P_ALL 0x3??????? 接收發(fā)往本機(jī)mac的所有類型ip arp rarp的數(shù)據(jù)幀, 接收從本機(jī)發(fā)出的所有類型的數(shù)據(jù)幀.(混雜模式打開的情況下,會(huì)接收到非發(fā)往本地mac的數(shù)據(jù)幀)
?
發(fā) 送的時(shí)候需要自己組織整個(gè)以太網(wǎng)數(shù)據(jù)幀.所有相關(guān)的地址使用struct sockaddr_ll 而不是struct sockaddr_in(因?yàn)閰f(xié)議簇是PF_PACKET不是AF_INET了),比如發(fā)送給某個(gè)機(jī)器,對(duì)方的地址需要使用struct sockaddr_ll.
?
這種socket大小通吃,強(qiáng)悍 linux socket調(diào)用與arp報(bào)文發(fā)送
Linux提供最常用的網(wǎng)絡(luò)通信應(yīng)用程序開發(fā)接口--Berkerley套接字(Socket).它既適用于同一主機(jī)上進(jìn)程間通信(IPC),又適用于不同主機(jī)上的進(jìn)程間通信。套接字的設(shè)置通過socket調(diào)用完成:

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

其中family指通信域或協(xié)議族,Linux系統(tǒng)支持的網(wǎng)絡(luò)協(xié)議族有PF_UNIX,PF_IPX,PF_PACKET等幾十種;type為套接字類型,目前有SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET等;protocol是套接字所用的特定協(xié)議類型號(hào).

Linux系統(tǒng)提供的基于數(shù)據(jù)鏈路層開發(fā)應(yīng)用程序的接口集成在套接字中,它是通過創(chuàng)建packet類型的套接宇.使應(yīng)用程序可直接在數(shù)據(jù)鏈路層接收或發(fā)送未被系統(tǒng)處理的原始的數(shù)據(jù)報(bào)文(如ARP報(bào)文),用戶也可以使用packet類型的套接宇在物理層上定義自己特殊的網(wǎng)絡(luò)協(xié)議。只有注冊(cè)號(hào)為0的用戶(超級(jí)用戶)進(jìn)程才能建立或打開用于訪問網(wǎng)絡(luò)低層的套接字.在Linux系統(tǒng)中,用以下三種方式創(chuàng)建的packet套接字可直接用于訪問數(shù)據(jù)鏈路層:
(1)PF_INET協(xié)議族中SOCK_PACKEI類型的套接字
(2)PF_PACKET協(xié)議族中SOCK_RAW類型的套接字
(3)PF_PACKET協(xié)議族中SOCK_DGRAM類型的套接字

Linux 2.0中對(duì)數(shù)據(jù)鏈路層的操作主要使用SOCK_PACKET定義的packet套接字.初始化定義如下:
sockfd=socket(AF_INET,SOCK_PACKET,protocol);
其中,protocol用于決定套接字所使用的物理層協(xié)議(在IEEE802.3中定義).筆者在此選擇常用的物理層協(xié)議ETH_P_IP(Internet協(xié)議).SOCK_PACKET使用一種比較老的sockaddr_pkt數(shù)據(jù)結(jié)構(gòu)來設(shè)置網(wǎng)絡(luò)接口。

在Linux 2 2中使用PF_PACKET代替SOCK_PACKET來定義packet套接字.這種套接字的初始化定義如下:
sockfd=socket(PF_PACKET,socket_type,protocol);
其中socket_type只能為SOCK_RAW或SOCK_DGRAM,protocol為物理層通信協(xié)議(同上)。SOCK_RAW和SOCK_DGRAM類型套接字使用一種與設(shè)備無關(guān)的標(biāo)準(zhǔn)物理層地址結(jié)構(gòu)sockaddr_ll,但具體操作的報(bào)文格式不同。SOCK_RAW套接字直接向網(wǎng)絡(luò)硬件驅(qū)動(dòng)程序發(fā)送(或從網(wǎng)絡(luò)硬件驅(qū)動(dòng)程序接收)沒有任何處理的完整數(shù)據(jù)報(bào)文(包括物理幀的幀頭),這就要求程序員必須了解對(duì)應(yīng)設(shè)備的物理幀幀頭結(jié)構(gòu),才能正確地裝載和分析報(bào)文。SOCK_DGRAM套接字收到的數(shù)據(jù)報(bào)文的物理幀幀頭會(huì)被系統(tǒng)自動(dòng)去掉,同樣,在發(fā)送時(shí).系統(tǒng)將會(huì)根據(jù)sockaddr_ll結(jié)構(gòu)中的目的地址信息為數(shù)據(jù)報(bào)文舔加一個(gè)臺(tái)適的物理幀幀頭。

默認(rèn)情況下.從任何接口收到的符合指定協(xié)議的所有數(shù)據(jù)報(bào)文都會(huì)被傳送到packet套接字。使用bind系統(tǒng)調(diào)用以一個(gè)sochddr_l1地址結(jié)構(gòu)將paccket套接字與某個(gè)網(wǎng)絡(luò)接口相綁定,可使套接字只接收指定接口的
數(shù)據(jù)報(bào)文.socaddr_ll地址結(jié)構(gòu)定義如下:
struct sockaddr_ll
{
unsigned short sll_family; /* 總是 AF_PACKET */
unsigned short sll_protocol; /* 物理層的協(xié)議 */
int sll_ifindex; /* 接口號(hào) */
unsigned short sll_hatype; /* 報(bào)頭類型 */
unsigned char sll_pkttype; /* 分組類型 */
unsigned char sll_halen; /* 地址長(zhǎng)度 */
unsigned char sll_addr[8]; /* 物理層地址 */
};

一、利用PF_lNET協(xié)議族中SOCK_PACKET類型的套接宇實(shí)現(xiàn)ARP
(1)建套接字
創(chuàng)建套接宇采用socket系統(tǒng)調(diào)用,格式如下:
sockfd=socket(PF_INET,SOCK_PACKET,htons(ETH_P_ARP));
(2)裝載報(bào)文
對(duì)于SOCK_PACKET類型的套接字,以太網(wǎng)物理幀頭應(yīng)作為所發(fā)送報(bào)文一部分由程序員設(shè)置,物理幀頭的格式定義如下:(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 };
實(shí)際發(fā)送的地址解析報(bào)文幀由以太網(wǎng)物理幀頭與幀數(shù)據(jù)(ARP報(bào)文)共同組成,用結(jié)構(gòu)體ARPPACKET表
示如下:
typedef struct {
struct ethhdr eth_header; //struct defined in linux/if_ether.h
ARPHDR arp_header;
}ARPPACKET;
上述報(bào)文結(jié)構(gòu)的裝載比較簡(jiǎn)單。對(duì)ARP部分,arp_header的設(shè)置如下:
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[]分別填入本機(jī)的物理地址、ip地址和要解析的對(duì)方主機(jī)的ip地址.返回報(bào)文中pkt.arp_header.tha[]中的內(nèi)容就是解析
得到的對(duì)方主機(jī)的物理地址。

對(duì)于以太網(wǎng)幀頭部分,pkt.eth_header.h_dest[]為目的地址,即廣播物理地址0xFFFFFF, pkt.eth_header.source[]為本機(jī)物理地址(同pkt.arp_header.ar_sha[]),
pkt.eth_header.h_proto賦值htons(ETHERTYPE_ARP)表示為地址解析類型報(bào)文。
ETHERTYPE_ARP與ETH_P_ARP的值都是0x0806,只是定義的文件不同。前者定義在net/ethernet.h,后者定義在linux/if_ether.h

(3)報(bào)文的發(fā)送與接收
在數(shù)據(jù)鏈路層發(fā)送/接收?qǐng)?bào)文與在IP層發(fā)送/接收數(shù)據(jù)報(bào)文類似,分別用系統(tǒng)調(diào)用sendto()和recvfrom()
完成,只是要將配置好的含有目標(biāo)地址的報(bào)文發(fā)往本地網(wǎng)絡(luò)硬件而不是目標(biāo)主機(jī)。相應(yīng)的程序段如下:
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為包含結(jié)構(gòu)體ARPPACKET的字符型指針。

通過檢驗(yàn)所接收到的ARP應(yīng)答報(bào)文中arp_header.ar_op項(xiàng)是否為ARPOP_REPLY(ARP應(yīng)答)同時(shí)arp_header.ar_tip是否為已知的對(duì)方主機(jī)的IP地址來判斷所得到的解析地址是否正確.


二、利用PF_PACKET協(xié)議族中SOCK_RAW類型的套接字實(shí)現(xiàn)ARP
(1)創(chuàng)建套接字
sockfd=socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ARP));
(2)裝載報(bào)文
與SOCK_PACKET類型的套接字相同,SOCK_RAW類型的套接字對(duì)鏈路層操作時(shí),也要求以太網(wǎng)物理幀頭應(yīng)作為所發(fā)送報(bào)文一部分由程序員設(shè)置.
(3)報(bào)文的發(fā)送與接收
SOCK_RAW類型套接字使用標(biāo)準(zhǔn)的物理層地址結(jié)構(gòu)sockaddr_ll,所以,報(bào)文發(fā)送之前,應(yīng)將套接字綁定到(使用bind()系統(tǒng)調(diào)用)配置好的本地物理地址結(jié)構(gòu)my_etheraddr,同時(shí)還需配置目的物理地址結(jié)構(gòu)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; /*接口號(hào)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]中放入本主機(jī)的物理地址。

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

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

發(fā)送與接收調(diào)用程序如下:
sendto(sockfd,buf,sizeof(struct ARPPACKET),0,
(struct sockaddr *)&broad_etheraddr,sizeof(broad_etheraddr));

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

三、利用PF_PACKET協(xié)議族中SOCK_DGRAM類型的套接字實(shí)現(xiàn)ARP
SOCK_DGRAM類型的套接字不要求程序員配置以太網(wǎng)幀頭,所以所發(fā)送的報(bào)文只有數(shù)據(jù)區(qū)(ARP報(bào)文)部分,其它與SOCK_RAW類型的套接字相同。

總結(jié)

以上是生活随笔為你收集整理的linux sock_raw原始套接字编程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。