新聞中心
Linux原始套接字編程是指在Linux操作系統(tǒng)中,使用套接字API對網(wǎng)絡(luò)數(shù)據(jù)包進(jìn)行原始訪問和操作的編程技術(shù)。它給開發(fā)者提供了極大的自由度和靈活性,能夠?qū)崿F(xiàn)從網(wǎng)絡(luò)底層到應(yīng)用層的各種操作,比如捕獲網(wǎng)絡(luò)數(shù)據(jù)包、修改數(shù)據(jù)包內(nèi)容、發(fā)送自定義數(shù)據(jù)包等。下面將對Linux原始套接字編程進(jìn)行簡單介紹。

創(chuàng)新互聯(lián)建站專注于企業(yè)全網(wǎng)營銷推廣、網(wǎng)站重做改版、曲沃網(wǎng)站定制設(shè)計、自適應(yīng)品牌網(wǎng)站建設(shè)、H5建站、商城網(wǎng)站定制開發(fā)、集團(tuán)公司官網(wǎng)建設(shè)、成都外貿(mào)網(wǎng)站建設(shè)公司、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁設(shè)計等建站業(yè)務(wù),價格優(yōu)惠性價比高,為曲沃等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。
1. 原始套接字概述
原始套接字本質(zhì)上是一種與傳輸層協(xié)議無關(guān)的套接字類型,它可以對傳輸層及其以下的網(wǎng)絡(luò)協(xié)議棧數(shù)據(jù)報文進(jìn)行底層的網(wǎng)絡(luò)數(shù)據(jù)包操作。在Linux系統(tǒng)中,原始套接字是通過socket()系統(tǒng)調(diào)用創(chuàng)建的,如下所示:
“`c
#include
int socket(int domn, int type, int protocol);
“`
其中,domn參數(shù)指定套接字的通信協(xié)議族,type參數(shù)指定套接字類型,protocol參數(shù)在原始套接字中一般設(shè)置為0。
原始套接字與普通套接字的更大區(qū)別在于,它可以讓應(yīng)用程序接收和發(fā)送參照數(shù)據(jù)鏈路層協(xié)議的數(shù)據(jù)包,而不像TCP、UDP等傳輸層協(xié)議會對數(shù)據(jù)進(jìn)行分段、重組和重傳等操作。
2. 數(shù)據(jù)包捕獲
原始套接字最常用的功能之一是捕獲網(wǎng)絡(luò)數(shù)據(jù)包,可以用于網(wǎng)絡(luò)分析、嗅探等諸多場景。以下是一個簡單的代碼例子,演示如何使用原始套接字捕獲網(wǎng)絡(luò)數(shù)據(jù)包:
“`c
#include
#include
#include
#include
#include
#include
#define MAX_BUFFER_SIZE 2023
int mn()
{
int raw_socket;
struct sockaddr_in server;
char buffer[MAX_BUFFER_SIZE] = {0};
// 創(chuàng)建原始套接字
raw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
if (raw_socket
perror(“socket”);
return -1;
}
// 填充Server端地址
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr(“192.168.1.10”);
// 綁定套接字
if (bind(raw_socket, (struct sockaddr *)&server, sizeof(server))
perror(“bind”);
return -1;
}
// 接收數(shù)據(jù)包
while (1) {
int size = recvfrom(raw_socket, buffer, MAX_BUFFER_SIZE, 0, NULL, NULL);
if (size
perror(“recvfrom”);
return -1;
}
printf(“Received %d bytes packet\n”, size);
}
// 關(guān)閉套接字
close(raw_socket);
return 0;
}
“`
代碼中首先使用socket()函數(shù)創(chuàng)建了一個原始套接字,然后將其綁定在指定的服務(wù)器IP地址上。通過循環(huán)調(diào)用recvfrom()函數(shù),不斷接收從網(wǎng)絡(luò)中來的數(shù)據(jù)包,并打印收到的數(shù)據(jù)包長度。
這個例子僅捕獲TCP協(xié)議的數(shù)據(jù)包,可以通過在socket()函數(shù)中指定不同的協(xié)議參數(shù)來實現(xiàn)原始套接字的多種用途。
3. 數(shù)據(jù)包發(fā)送
除了數(shù)據(jù)包捕獲,原始套接字還可以用于自定義的網(wǎng)絡(luò)數(shù)據(jù)包發(fā)送。以下是一個簡單的例子,演示如何使用原始套接字發(fā)送一個Ping包:
“`c
#include
#include
#include
#include
#include
#include
#define MAX_BUFFER_SIZE 2023
unsigned short checksum(unsigned short *buf, int n)
{
unsigned long sum = 0;
while (n > 1) {
sum += *buf++;
n -= 2;
}
if (n == 1) {
sum += *(unsigned char *)buf;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return (unsigned short)(~sum);
}
int mn()
{
int raw_socket;
struct sockaddr_in server;
char buffer[MAX_BUFFER_SIZE] = {0};
struct iphdr *ip_header;
struct icmphdr *icmp_header;
// 創(chuàng)建原始套接字
raw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (raw_socket
perror(“socket”);
return -1;
}
// 填充Server端地址
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr(“192.168.1.1”);
// 準(zhǔn)備IP頭和ICMP頭
ip_header = (struct iphdr *)buffer;
icmp_header = (struct icmphdr *)(buffer + sizeof(struct iphdr));
ip_header->ihl = 5;
ip_header->version = 4;
ip_header->tos = 0;
ip_header->tot_len = sizeof(struct iphdr) + sizeof(struct icmphdr);
ip_header->id = htons(0x1234);
ip_header->frag_off = 0;
ip_header->ttl = 255;
ip_header->protocol = IPPROTO_ICMP;
ip_header->saddr = INADDR_ANY;
ip_header->daddr = server.sin_addr.s_addr;
icmp_header->type = ICMP_ECHO;
icmp_header->code = 0;
icmp_header->un.echo.id = htons(0x5678);
icmp_header->un.echo.sequence = htons(1);
icmp_header->checksum = checksum((unsigned short *)icmp_header, sizeof(struct icmphdr));
// 發(fā)送Ping包
int size = sendto(raw_socket, buffer, ip_header->tot_len, 0, (struct sockaddr *)&server, sizeof(server));
if (size
perror(“sendto”);
return -1;
}
printf(“Sent %d bytes packet\n”, size);
// 關(guān)閉套接字
close(raw_socket);
return 0;
}
“`
代碼中首先使用socket()函數(shù)創(chuàng)建了一個原始套接字,然后準(zhǔn)備了IP頭和ICMP頭,填充后使用sendto()函數(shù)發(fā)送到目標(biāo)服務(wù)器上。
對于Sendto()函數(shù)來說,發(fā)送的數(shù)據(jù)長度應(yīng)該是網(wǎng)絡(luò)協(xié)議下應(yīng)有的長度,所以在IP頭中需要設(shè)置IP報文的總長度。另外,ICMP報文中的字段un.echo.sequence是由發(fā)送端的序列號,因此它應(yīng)該發(fā)送該字段的反向字節(jié)序。
4.
相關(guān)問題拓展閱讀:
- linux下IP地址欺騙(利用原始套接字)
- linux socket 如何發(fā)現(xiàn)主機(jī)是否活著
linux下IP地址欺騙(利用原始套接字)
發(fā)了你一個ARP包構(gòu)建的,你自己可以填充IP。數(shù)據(jù)包都是可以自己隨意偽造的:)。
linux socket 如何發(fā)現(xiàn)主機(jī)是否活著
挨個telnet +端口 如果能進(jìn)去說明活著,否則就死了
使用基本socket函數(shù)來檢測。
Linux系統(tǒng)是通過提供套接字(socket)來進(jìn)行網(wǎng)絡(luò)編程的。網(wǎng)絡(luò)的socket數(shù)據(jù)傳輸是一種特殊的I/O,socket也是一種文件描述符。socket也有一個類似于打
開文件的函數(shù):socket(),調(diào)用socket(),該函數(shù)返回一個巧神整型的socket的描述符,隨后的連接建立、數(shù)據(jù)傳輸?shù)炔僮饕捕际峭ㄟ^該socket實現(xiàn)。
1、socket函數(shù)
syntax:
int socket(int domain, int type, int protocol);
功能說明:
調(diào)用成功,返回socket文件描述符;失敗,返回-1,并設(shè)置errno
參數(shù)說明:
domain指明所使用的協(xié)議族,通常為PF_INET,表示TCP/IP協(xié)議;
type參數(shù)指定socket的類型,基本上有三談姿種:數(shù)據(jù)流套接字、數(shù)據(jù)報套接字、原始套接字
protocol通常賦值”0″。
兩個網(wǎng)絡(luò)程序之間的一個網(wǎng)絡(luò)連接包括五種信息:通信協(xié)議、本地協(xié)議地址、本地主機(jī)端口、遠(yuǎn)端主機(jī)地址和遠(yuǎn)端協(xié)議端口。socket數(shù)據(jù)結(jié)構(gòu)中包含這五種信息。
2、bind函數(shù)
syntax:
int bind(int sock_fd,struct sockaddr_in *my_addr, int addrlen);
功能說明:
將套接字和指定的端口相連。成功返回0,否則,返回-1,并置errno.
參數(shù)說明:
sock_fd是調(diào)用socket函數(shù)返回值,
my_addr是一個指向包含有本機(jī)IP地址及端口號等信息的sockaddr類型的指針;
struct sockaddr_in結(jié)構(gòu)類型是用來保存socket信息的:
struct sockaddr_in {
short int sin_family;
unsigned short int sin_port;
struct in_addr sin_addr;
unsigned char sin_zero;
};
addrlen為sockaddr的長度。
3、connect函數(shù)
syntax:
int connect(int sock_fd, struct sockaddr *serv_addr,int addrlen);
功能說明:
客戶端發(fā)送服務(wù)請求。成功返回0,否則返回-1,并置errno。
參數(shù)說明:
sock_fd 是socket函數(shù)返回的socket描述符;serv_addr是包含遠(yuǎn)端主機(jī)IP地址和端口號的指針;addrlen是結(jié)構(gòu)sockaddr_in的長度。
4、listen函數(shù)
syntax:
int listen(int sock_fd, int backlog);
功能說明:
等待指定的端口的出現(xiàn)客戶端連接。調(diào)用成功返回0,否則,返回-1,并置errno.
參數(shù)說明:
sock_fd 是socket()函數(shù)返回值;
backlog指定在請求隊列中允許的更大請求數(shù)
5、accecpt函數(shù)
syntax:
int accept(int sock_fd, struct sockadd_in* addr, int addrlen);
功能說明:
用于接受客戶端的服務(wù)請求,成功返回新的套接字描述符,失敗返回-1,并置errno。
參數(shù)說明:
sock_fd是被監(jiān)聽的socket描述符,
addr通常是一個指向sockaddr_in變量的指針,
addrlen是結(jié)構(gòu)sockaddr_in的長度。
6、write函數(shù)
syntax:
ssize_t write(int fd,const void *buf,size_t nbytes)
功能說明:
write函數(shù)將buf中的nbytes字節(jié)內(nèi)容寫入文件描述符fd.成功時返回寫的字節(jié)數(shù).失敗時返回-1. 并設(shè)置errno變量.
在網(wǎng)絡(luò)程序中,當(dāng)我們向套接字文件描述符寫時有倆種可能:
)write的返回值大于0,表示寫了部分或者是全部的數(shù)據(jù).
)返回的值小于0,此時出現(xiàn)了錯誤.需要根據(jù)錯誤類型來處理.
如果錯誤為EINTR表示在寫的時候出現(xiàn)了中斷錯誤含寬絕.
如果錯誤為EPIPE表示網(wǎng)絡(luò)連接出現(xiàn)了問題.
7、read函數(shù)
syntax:
ssize_t read(int fd,void *buf,size_t nbyte)
函數(shù)說明:
read函數(shù)是負(fù)責(zé)從fd中讀取內(nèi)容.當(dāng)讀成功時,read返回實際所讀的字節(jié)數(shù),如果返回的值是0 表示已經(jīng)讀到文件的結(jié)束了,小于0表示出現(xiàn)了錯誤.
如果錯誤為EINTR說明讀是由中斷引起的,
如果錯誤是ECONNREST表示網(wǎng)絡(luò)連接出了問題.
8、close函數(shù)
syntax:
int close(sock_fd);
說明:
當(dāng)所有的數(shù)據(jù)操作結(jié)束以后,你可以調(diào)用close()函數(shù)來釋放該socket,從而停止在該socket上的任何數(shù)據(jù)操作:
函數(shù)運行成功返回0,否則返回-1
你可以用掃描端口的方式,做個循環(huán)
socket
connect
原始套接字編程 linux的介紹就聊到這里吧,感謝你花時間閱讀本站內(nèi)容,更多關(guān)于原始套接字編程 linux,Linux原始套接字編程簡述,linux下IP地址欺騙(利用原始套接字),linux socket 如何發(fā)現(xiàn)主機(jī)是否活著的信息別忘了在本站進(jìn)行查找喔。
香港服務(wù)器選創(chuàng)新互聯(lián),2H2G首月10元開通。
創(chuàng)新互聯(lián)(www.cdcxhl.com)互聯(lián)網(wǎng)服務(wù)提供商,擁有超過10年的服務(wù)器租用、服務(wù)器托管、云服務(wù)器、虛擬主機(jī)、網(wǎng)站系統(tǒng)開發(fā)經(jīng)驗。專業(yè)提供云主機(jī)、虛擬主機(jī)、域名注冊、VPS主機(jī)、云服務(wù)器、香港云服務(wù)器、免備案服務(wù)器等。
文章題目:Linux原始套接字編程簡述(原始套接字編程linux)
本文路徑:http://fisionsoft.com.cn/article/cdsgihc.html


咨詢
建站咨詢
