【Linux网络编程】原始套接字编程
原始套接字編程和之前的 UDP 編程差不多,無非就是創建一個套接字后,通過這個套接字接收數據或者發送數據。區別在于,原始套接字可以自行組裝數據包(偽裝本地 IP,本地 MAC),可以接收本機網卡上所有的數據幀(數據包)。另外,必須在管理員權限下才能使用原始套接字。
原始套接字的創建
int socket ( int family, int type, int protocol );
參數:
family:協議族 這里寫?PF_PACKET
type: ?套接字類,這里寫?SOCK_RAW
protocol:協議類別,指定可以接收或發送的數據包類型,不能寫 “0”,取值如下,注意,傳參時需要用?htons() 進行字節序轉換。
ETH_P_IP:IPV4數據包
ETH_P_ARP:ARP數據包
ETH_P_ALL:任何協議類型的數據包
返回值:
成功( >0 ):套接字,這里為鏈路層的套接字
失敗( <0 ):出錯
實例如下:
// 所需頭文件 #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; }
獲取鏈路層的數據包
ssize_t recvfrom( ?int sockfd,?
void *buf,?
size_t nbytes,
int flags,
struct sockaddr *from,?
socklen_t *addrlen );
參數:
sockfd:原始套接字
buf:接收數據緩沖區
nbytes:接收數據緩沖區的大小
flags:套接字標志(常為0)
from:這里沒有用,寫 NULL
addrlen:這里沒有用,寫 NULL
返回值:
成功:接收到的字符數
失敗:-1
實例如下:
#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));//獲取鏈路層的數據包int len = recvfrom(sock_raw_fd, buf, sizeof(buf), 0, NULL, NULL);printf("len = %d\n", len);return 0; }
混雜模式
默認的情況下,我們接收數據,目的地址是本地地址,才會接收。有時候我們想接收所有經過網卡的所有數據流,而不論其目的地址是否是它,這時候我們需要設置網卡為混雜模式。
網卡的混雜模式一般在網絡管理員分析網絡數據作為網絡故障診斷手段時用到,同時這個模式也被網絡黑客利用來作為網絡數據竊聽的入口。在 Linux 操作系統中設置網卡混雜模式時需要管理員權限。在 Windows 操作系統和 Linux 操作系統中都有使用混雜模式的抓包工具,比如著名的開源軟件 Wireshark。
通過命令給 Linux 網卡設置混雜模式(需要管理員權限)
設置混雜模式:ifconfig eth0 promisc
取消混雜模式:ifconfig eth0 -promisc
通過代碼給 Linux?網卡設置混雜模式
代碼如下:
struct ifreq req; //網絡接口地址strncpy(req.ifr_name, "eth0", IFNAMSIZ); //指定網卡名稱 if(-1 == ioctl(sock_raw_fd, SIOCGIFINDEX, &req)) //獲取網絡接口 {perror("ioctl");close(sock_raw_fd);exit(-1); }req.ifr_flags |= IFF_PROMISC; if(-1 == ioctl(sock_raw_fd, SIOCSIFINDEX, &req)) //網卡設置混雜模式 {perror("ioctl");close(sock_raw_fd);exit(-1); }
發送自定義的數據包:
ssize_t sendto( ? int sockfd,
const void *buf,
size_t nbytes,int flags,
const struct sockaddr *to, ? ? ? ?
socklen_t addrlen );
參數:
sockfd:原始套接字
buf:發送數據緩沖區
nbytes:發送數據緩沖區的大小
flags:一般為 0
to:本機網絡接口,指發送的數據應該從本機的哪個網卡出去,而不是以前的目的地址
addrlen:to 所指向內容的長度
返回值:
成功:發送數據的字符數
失敗: -1
本機網絡接口的定義
發送完整代碼如下:
[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
總結
以上是生活随笔為你收集整理的【Linux网络编程】原始套接字编程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Linux网络编程】原始套接字能干什么
- 下一篇: 【Linux网络编程】原始套接字实例:M