自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Linux網(wǎng)絡(luò)編程:原始套接字編程及實(shí)例分析

網(wǎng)絡(luò) 通信技術(shù)
原始套接字編程和之前的UDP 編程差不多,無(wú)非就是創(chuàng)建一個(gè)套接字后,通過(guò)這個(gè)套接字接收數(shù)據(jù)或者發(fā)送數(shù)據(jù)。區(qū)別在于,原始套接字可以自行組裝數(shù)據(jù)包(偽裝本地 IP,本地 MAC),可以接收本機(jī)網(wǎng)卡上所有的數(shù)據(jù)幀(數(shù)據(jù)包)。另外,必須在管理員權(quán)限下才能使用原始套接字。

一、原始套接字能干什么?

通常情況下程序員接所接觸到的套接字(Socket)為兩類(lèi):

(1)流式套接字(SOCK_STREAM):一種面向連接的Socket,針對(duì)于面向連接的TCP 服務(wù)應(yīng)用;

(2)數(shù)據(jù)報(bào)式套接字(SOCK_DGRAM):一種無(wú)連接的Socket,對(duì)應(yīng)于無(wú)連接的UDP 服務(wù)應(yīng)用。

從用戶的角度來(lái)看,SOCK_STREAM、SOCK_DGRAM 這兩類(lèi)套接字似乎的確涵蓋了TCP/IP 應(yīng)用的全部,因?yàn)榛赥CP/IP 的應(yīng)用,從協(xié)議棧的層次上講,在傳輸層的確只可能建立于TCP 或 UDP協(xié)議之上,而SOCK_STREAM、SOCK_DGRAM 又分別對(duì)應(yīng)于TCP和UDP,所以幾乎所有的應(yīng)用都可以用這兩類(lèi)套接字實(shí)現(xiàn)。 

[[130856]] 

但是,當(dāng)我們面對(duì)如下問(wèn)題時(shí),SOCK_STREAM、SOCK_DGRAM 將顯得這樣無(wú)助:

(1)怎樣發(fā)送一個(gè)自定義的IP 包?

(2)怎樣發(fā)送一個(gè)ICMP 協(xié)議包?

(3)怎樣分析所有經(jīng)過(guò)網(wǎng)絡(luò)的包,而不管這樣包是否是發(fā)給自己的?

(4)怎樣偽裝本地的IP 地址?

這使得我們必須面對(duì)另外一個(gè)深刻的主題——原始套接字(SOCK_RAW)。原始套接字廣泛應(yīng)用于高級(jí)網(wǎng)絡(luò)編程,也是一種廣泛的黑客手段。著名的網(wǎng)絡(luò)sniffer(一種基于被動(dòng)偵聽(tīng)原理的網(wǎng)絡(luò)分析方式)、拒絕服務(wù)攻擊(DOS)、IP 欺騙等都可以通過(guò)原始套接字實(shí)現(xiàn)。

原始套接字(SOCK_RAW)可以用來(lái)自行組裝數(shù)據(jù)包,可以接收本機(jī)網(wǎng)卡上所有的數(shù)據(jù)幀(數(shù)據(jù)包),對(duì)于監(jiān)聽(tīng)網(wǎng)絡(luò)流量和分析網(wǎng)絡(luò)數(shù)據(jù)很有作用。

原始套接字是基于IP 數(shù)據(jù)包的編程(SOCK_PACKET 是基于數(shù)據(jù)鏈路層的編程)。另外,必須在管理員權(quán)限下才能使用原始套接字。

原始套接字(SOCK_RAW)與標(biāo)準(zhǔn)套接字(SOCK_STREAM、SOCK_DGRAM)的區(qū)別在于原始套接字直接置“根”于操作系統(tǒng)網(wǎng)絡(luò)核心(Network Core),而 SOCK_STREAM、SOCK_DGRAM 則“懸浮”于 TCP 和 UDP 協(xié)議的外圍。 

[[130857]] 

流式套接字只能收發(fā) TCP 協(xié)議的數(shù)據(jù),數(shù)據(jù)報(bào)套接字只能收發(fā) UDP 協(xié)議的數(shù)據(jù),原始套接字可以收發(fā)內(nèi)核沒(méi)有處理的數(shù)據(jù)包。

#p#

二、原始套接字編程

原始套接字編程和之前的UDP 編程差不多,無(wú)非就是創(chuàng)建一個(gè)套接字后,通過(guò)這個(gè)套接字接收數(shù)據(jù)或者發(fā)送數(shù)據(jù)。區(qū)別在于,原始套接字可以自行組裝數(shù)據(jù)包(偽裝本地 IP,本地 MAC),可以接收本機(jī)網(wǎng)卡上所有的數(shù)據(jù)幀(數(shù)據(jù)包)。另外,必須在管理員權(quán)限下才能使用原始套接字。

原始套接字的創(chuàng)建:

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

參數(shù):

family:協(xié)議族 這里寫(xiě) PF_PACKET

type: 套接字類(lèi),這里寫(xiě) SOCK_RAW

protocol:協(xié)議類(lèi)別,指定可以接收或發(fā)送的數(shù)據(jù)包類(lèi)型,不能寫(xiě) “0”,取值如下,注意,傳參時(shí)需要用 htons() 進(jìn)行字節(jié)序轉(zhuǎn)換。

ETH_P_IP:IPV4數(shù)據(jù)包

ETH_P_ARP:ARP數(shù)據(jù)包

ETH_P_ALL:任何協(xié)議類(lèi)型的數(shù)據(jù)包

返回值:

成功( >0 ):套接字,這里為鏈路層的套接字

失敗( <0 ):出錯(cuò)

實(shí)例如下:

  1. // 所需頭文件    
  2. #include <sys/socket.h>    
  3. #include <netinet/ether.h>    
  4. #include <stdio.h>  // perror    
  5.     
  6. int main(int argc,charchar *argv[])    
  7. {    
  8.     int sock_raw_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL) );    
  9.     
  10.     if(sock_raw_fd < 0){    
  11.         perror("socket");    
  12.         return -1;    
  13.     }    
  14.         
  15.     return 0;    
  16. }   

獲取鏈路層的數(shù)據(jù)包:

ssize_t recvfrom( int sockfd,

void *buf,

size_t nbytes,

int flags,

struct sockaddr *from,

socklen_t *addrlen );

參數(shù):

sockfd: 原始套接字

buf: 接收數(shù)據(jù)緩沖區(qū)

nbytes: 接收數(shù)據(jù)緩沖區(qū)的大小

flags: 套接字標(biāo)志(常為0)

from: 這里沒(méi)有用,寫(xiě) NULL

addrlen:這里沒(méi)有用,寫(xiě) NULL

返回值:

成功:接收到的字符數(shù)

失敗:-1

實(shí)例如下:

  1. #include <stdio.h>    
  2. #include <netinet/in.h>    
  3. #include <sys/socket.h>    
  4. #include <netinet/ether.h>    
  5.     
  6. int main(int argc,charchar *argv[])    
  7. {    
  8.     unsigned char buf[1024] = {0};    
  9.     int sock_raw_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));    
  10.     
  11.     //獲取鏈路層的數(shù)據(jù)包    
  12.     int len = recvfrom(sock_raw_fd, buf, sizeof(buf), 0, NULL, NULL);    
  13.     printf("len = %d\n", len);    
  14.     
  15.     return 0;    
  16. }   

混雜模式

默認(rèn)的情況下,我們接收數(shù)據(jù),目的地址是本地地址,才會(huì)接收。有時(shí)候我們想接收所有經(jīng)過(guò)網(wǎng)卡的所有數(shù)據(jù)流,而不論其目的地址是否是它,這時(shí)候我們需要設(shè)置網(wǎng)卡為混雜模式。

網(wǎng)卡的混雜模式一般在網(wǎng)絡(luò)管理員分析網(wǎng)絡(luò)數(shù)據(jù)作為網(wǎng)絡(luò)故障診斷手段時(shí)用到,同時(shí)這個(gè)模式也被網(wǎng)絡(luò)黑客利用來(lái)作為網(wǎng)絡(luò)數(shù)據(jù)竊聽(tīng)的入口。在 Linux 操作系統(tǒng)中設(shè)置網(wǎng)卡混雜模式時(shí)需要管理員權(quán)限。在 Windows 操作系統(tǒng)和 Linux 操作系統(tǒng)中都有使用混雜模式的抓包工具,比如著名的開(kāi)源軟件 Wireshark。

通過(guò)命令給 Linux 網(wǎng)卡設(shè)置混雜模式(需要管理員權(quán)限)

設(shè)置混雜模式:ifconfig eth0 promisc 

[[130858]] 

取消混雜模式:ifconfig eth0 -promisc 

[[130859]] 

通過(guò)代碼給 Linux 網(wǎng)卡設(shè)置混雜模式 

[[130860]] 

代碼如下:

  1. struct ifreq ethreq;    //網(wǎng)絡(luò)接口地址    
  2.         
  3. strncpy(ethreq.ifr_name, "eth0", IFNAMSIZ);         //指定網(wǎng)卡名稱(chēng)    
  4. if(-1 == ioctl(sock_raw_fd, SIOCGIFINDEX, &ethreq)) //獲取網(wǎng)絡(luò)接口    
  5. {    
  6.     perror("ioctl");    
  7.     close(sock_raw_fd);    
  8.     exit(-1);    
  9. }    
  10.     
  11. ethreq.ifr_flags |= IFF_PROMISC;    
  12. if(-1 == ioctl(sock_raw_fd, SIOCSIFINDEX, &ethreq)) //網(wǎng)卡設(shè)置混雜模式    
  13. {    
  14.     perror("ioctl");    
  15.     close(sock_raw_fd);    
  16.     exit(-1);    
  17. }   

發(fā)送自定義的數(shù)據(jù)包:

ssize_t sendto( int sockfd,

const void *buf,

size_t nbytes,int flags,

const struct sockaddr *to,

socklen_t addrlen );

參數(shù):

sockfd: 原始套接字

buf: 發(fā)送數(shù)據(jù)緩沖區(qū)

nbytes: 發(fā)送數(shù)據(jù)緩沖區(qū)的大小

flags: 一般為 0

to: 本機(jī)網(wǎng)絡(luò)接口,指發(fā)送的數(shù)據(jù)應(yīng)該從本機(jī)的哪個(gè)網(wǎng)卡出去,而不是以前的目的地址

addrlen:to 所指向內(nèi)容的長(zhǎng)度

返回值:

成功:發(fā)送數(shù)據(jù)的字符數(shù)

失敗: -1

本機(jī)網(wǎng)絡(luò)接口的定義 

[[130861]] 

發(fā)送完整代碼如下:

  1. struct sockaddr_ll sll;                 //原始套接字地址結(jié)構(gòu)    
  2. struct ifreq ethreq;                    //網(wǎng)絡(luò)接口地址    
  3.     
  4. strncpy(ethreq.ifr_name, "eth0", IFNAMSIZ);         //指定網(wǎng)卡名稱(chēng)    
  5. if(-1 == ioctl(sock_raw_fd, SIOCGIFINDEX, ðreq))    //獲取網(wǎng)絡(luò)接口    
  6. {    
  7.     perror("ioctl");    
  8.     close(sock_raw_fd);    
  9.     exit(-1);    
  10. }    
  11.     
  12. /*將網(wǎng)絡(luò)接口賦值給原始套接字地址結(jié)構(gòu)*/    
  13. bzero(&sll, sizeof(sll));    
  14. sll.sll_ifindex = ethreq.ifr_ifindex;    
  15.     
  16. // 發(fā)送數(shù)據(jù)    
  17. // send_msg, msg_len 這里還沒(méi)有定義,模擬一下    
  18. int len = sendto(sock_raw_fd, send_msg, msg_len, 0 , (struct sockaddr *)&sll, sizeof(sll));    
  19. if(len == -1)    
  20. {    
  21.     perror("sendto");    
  22. }   

這里頭文件情況如下:

  1. #include <net/if.h>// struct ifreq    
  2. #include <sys/ioctl.h> // ioctl、SIOCGIFADDR    
  3. #include <sys/socket.h> // socket    
  4. #include <netinet/ether.h> // ETH_P_ALL    
  5. #include <netpacket/packet.h> // struct sockaddr_ll 

#p#

三、原始套接字實(shí)例:MAC頭部報(bào)文分析

由上得知,我們可以通過(guò)原始套接字以及 recvfrom( ) 可以獲取鏈路層的數(shù)據(jù)包,那我們接收的鏈路層數(shù)據(jù)包到底長(zhǎng)什么樣的呢?

鏈路層封包格式 

[[130862]] 

MAC 頭部(有線局域網(wǎng)) 

[[130863]] 

注意:CRC、PAD 在組包時(shí)可以忽略

鏈路層數(shù)據(jù)包的其中一種情況:

  1. unsigned char msg[1024] = {    
  2.     //--------------組MAC--------14------    
  3.     0xb8, 0x88, 0xe3, 0xe1, 0x10, 0xe6, // dst_mac: b8:88:e3:e1:10:e6    
  4.     0xc8, 0x9c, 0xdc, 0xb7, 0x0f, 0x19, // src_mac: c8:9c:dc:b7:0f:19    
  5.     0x08, 0x00,                         // 類(lèi)型:0x0800 IP協(xié)議    
  6.     // …… ……    
  7.     // …… ……    
  8. };   

接收的鏈路層數(shù)據(jù)包,并對(duì)其進(jìn)行簡(jiǎn)單分析:

  1. #include <stdio.h>    
  2. #include <string.h>    
  3. #include <stdlib.h>    
  4. #include <sys/socket.h>    
  5. #include <netinet/in.h>    
  6. #include <arpa/inet.h>    
  7. #include <netinet/ether.h>    
  8.     
  9. int main(int argc,charchar *argv[])    
  10. {    
  11.     int i = 0;    
  12.     unsigned char buf[1024] = "";    
  13.     int sock_raw_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));    
  14.     while(1)    
  15.     {    
  16.         unsigned char src_mac[18] = "";    
  17.         unsigned char dst_mac[18] = "";    
  18.         //獲取鏈路層的數(shù)據(jù)幀    
  19.         recvfrom(sock_raw_fd, buf, sizeof(buf),0,NULL,NULL);    
  20.         //從buf里提取目的mac、源mac    
  21.         sprintf(dst_mac,"%02x:%02x:%02x:%02x:%02x:%02x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);    
  22.         sprintf(src_mac,"%02x:%02x:%02x:%02x:%02x:%02x", buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]);    
  23.         //判斷是否為IP數(shù)據(jù)包    
  24.         if(buf[12]==0x08 && buf[13]==0x00)    
  25.         {       
  26.             printf("______________IP數(shù)據(jù)報(bào)_______________\n");    
  27.             printf("MAC:%s >> %s\n",src_mac,dst_mac);    
  28.         }//判斷是否為ARP數(shù)據(jù)包    
  29.         else if(buf[12]==0x08 && buf[13]==0x06)    
  30.         {    
  31.             printf("______________ARP數(shù)據(jù)報(bào)_______________\n");    
  32.             printf("MAC:%s >> %s\n",src_mac,dst_mac);    
  33.         }//判斷是否為RARP數(shù)據(jù)包    
  34.         else if(buf[12]==0x80 && buf[13]==0x35)    
  35.         {    
  36.             printf("______________RARP數(shù)據(jù)報(bào)_______________\n");    
  37.             printf("MAC:%s>>%s\n",src_mac,dst_mac);    
  38.         }    
  39.     }    
  40.     return 0;    
  41. }   

記得以管理者權(quán)限運(yùn)行程序:

 

[[130864]]
責(zé)任編輯:藍(lán)雨淚 來(lái)源: CSDN博客
相關(guān)推薦

2021-02-05 15:20:06

網(wǎng)絡(luò)安全套接字命令

2014-12-15 09:28:54

UDP

2015-05-28 10:47:38

Unix網(wǎng)絡(luò)編程TCP

2014-12-11 09:20:30

TCP

2012-01-06 13:58:47

JavaTCP

2020-10-15 19:10:05

LinuxAPI函數(shù)

2009-03-10 13:59:41

C#套接字編程

2015-10-16 09:33:26

TCPIP網(wǎng)絡(luò)協(xié)議

2021-03-14 18:22:23

套接字網(wǎng)絡(luò)通信

2014-12-17 09:22:10

網(wǎng)絡(luò)·安全技術(shù)周刊

2013-12-27 13:39:23

Java套接字

2009-06-30 16:51:56

2021-04-26 10:32:38

網(wǎng)絡(luò)安全PE編程工具

2021-04-30 18:50:44

網(wǎng)絡(luò)安全PE編程添加節(jié)區(qū)

2021-04-28 14:35:48

網(wǎng)絡(luò)安全PE編程代碼

2021-04-25 21:25:09

網(wǎng)絡(luò)安全網(wǎng)絡(luò)安全編程PE編程

2024-08-13 08:27:24

PythonTCP協(xié)議網(wǎng)絡(luò)編程

2009-12-18 09:54:10

Linux Shell

2009-07-06 18:24:56

Servlet實(shí)例

2021-01-18 10:35:18

網(wǎng)絡(luò)安全Windows代碼
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)