【Linux网络编程】原始套接字编程
原始套接字編程和之前的 UDP 編程差不多,無非就是創(chuàng)建一個套接字后,通過這個套接字接收數(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é)議族 這里寫?PF_PACKET
type: ?套接字類,這里寫?SOCK_RAW
protocol:協(xié)議類別,指定可以接收或發(fā)送的數(shù)據(jù)包類型,不能寫 “0”,取值如下,注意,傳參時需要用?htons() 進(jìn)行字節(jié)序轉(zhuǎn)換。
ETH_P_IP:IPV4數(shù)據(jù)包
ETH_P_ARP:ARP數(shù)據(jù)包
ETH_P_ALL:任何協(xié)議類型的數(shù)據(jù)包
返回值:
成功( >0 ):套接字,這里為鏈路層的套接字
失敗( <0 ):出錯
實(shí)例如下:
// 所需頭文件 #include <sys/socket.h> #include <netinet/ether.h> #include <stdio.h> // perrorint main(int argc,char *argv[]) {int sock_raw_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL) );if(sock_raw_fd < 0){perror("socket");return -1;}return 0; }
獲取鏈路層的數(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:這里沒有用,寫 NULL
addrlen:這里沒有用,寫 NULL
返回值:
成功:接收到的字符數(shù)
失敗:-1
實(shí)例如下:
#include <stdio.h> #include <netinet/in.h> #include <sys/socket.h> #include <netinet/ether.h>int main(int argc,char *argv[]) {unsigned char buf[1024] = {0};int sock_raw_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));//獲取鏈路層的數(shù)據(jù)包int len = recvfrom(sock_raw_fd, buf, sizeof(buf), 0, NULL, NULL);printf("len = %d\n", len);return 0; }
混雜模式
默認(rèn)的情況下,我們接收數(shù)據(jù),目的地址是本地地址,才會接收。有時候我們想接收所有經(jīng)過網(wǎng)卡的所有數(shù)據(jù)流,而不論其目的地址是否是它,這時候我們需要設(shè)置網(wǎng)卡為混雜模式。
網(wǎng)卡的混雜模式一般在網(wǎng)絡(luò)管理員分析網(wǎng)絡(luò)數(shù)據(jù)作為網(wǎng)絡(luò)故障診斷手段時用到,同時這個模式也被網(wǎng)絡(luò)黑客利用來作為網(wǎng)絡(luò)數(shù)據(jù)竊聽的入口。在 Linux 操作系統(tǒng)中設(shè)置網(wǎng)卡混雜模式時需要管理員權(quán)限。在 Windows 操作系統(tǒng)和 Linux 操作系統(tǒng)中都有使用混雜模式的抓包工具,比如著名的開源軟件 Wireshark。
通過命令給 Linux 網(wǎng)卡設(shè)置混雜模式(需要管理員權(quán)限)
設(shè)置混雜模式:ifconfig eth0 promisc
取消混雜模式:ifconfig eth0 -promisc
通過代碼給 Linux?網(wǎng)卡設(shè)置混雜模式
代碼如下:
struct ifreq req; //網(wǎng)絡(luò)接口地址strncpy(req.ifr_name, "eth0", IFNAMSIZ); //指定網(wǎng)卡名稱 if(-1 == ioctl(sock_raw_fd, SIOCGIFINDEX, &req)) //獲取網(wǎng)絡(luò)接口 {perror("ioctl");close(sock_raw_fd);exit(-1); }req.ifr_flags |= IFF_PROMISC; if(-1 == ioctl(sock_raw_fd, SIOCSIFINDEX, &req)) //網(wǎng)卡設(shè)置混雜模式 {perror("ioctl");close(sock_raw_fd);exit(-1); }
發(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ī)的哪個網(wǎng)卡出去,而不是以前的目的地址
addrlen:to 所指向內(nèi)容的長度
返回值:
成功:發(fā)送數(shù)據(jù)的字符數(shù)
失敗: -1
本機(jī)網(wǎng)絡(luò)接口的定義
發(fā)送完整代碼如下:
[cpp]?view plaincopy
這里頭文件情況如下:
#include <net/if.h>// struct ifreq #include <sys/ioctl.h> // ioctl、SIOCGIFADDR #include <sys/socket.h> // socket #include <netinet/ether.h> // ETH_P_ALL #include <netpacket/packet.h> // struct sockaddr_ll
總結(jié)
以上是生活随笔為你收集整理的【Linux网络编程】原始套接字编程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Linux网络编程】原始套接字能干什么
- 下一篇: 【Linux网络编程】原始套接字实例:M