sock_raw

sock_raw

理解一下SOCK_RAW的原理,比如網卡收到了一個 14+20+8+100+4(乙太網頭+ip頭+udp頭+數據+crc)的udp的乙太網數據幀.

sock_raw使用


(注意一定要在root下使用)原始套接字編程可以接收到本機網卡上的數據幀或者數據包,對與監聽網路的流量和分析是很有作用的。一共可以有3種方式創建這種socket
1.socket(AF_INET, SOCK_RAW, IPPROTO_TCP|IPPROTO_UDP|IPPROTO_ICMP)發送接收ip數據包,不能用IPPROTO_IP,因為如果是用了IPPROTO_IP,系統根本就不知道該用什麼協議。
2.socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL))發送接收乙太網數據幀
3.socket(AF_INET, SOCK_PACKET, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL))過時了,不要用啊

內容


協議類型

socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
能:該套接字可以接收協議類型為(tcp udp icmp等)發往本機的ip數據包,從上面看的就是20+8+100.
不能:不能收到非發往本地ip的數據包(ip軟過濾會丟棄這些不是發往本機ip的數據包).
不能:不能收到從本機發送出去的數據包.
發送的話需要自己組織tcp udp icmp等頭部。可以setsockopt來自己包裝ip頭部
這種套接字用來寫個ping程序比較適合
2. socket(PF_PACKET, SOCK_RAW, htons(x));
這個套接字比較強大,創建這種套接字可以監聽網卡上的所有數據幀。從上面看就是14+20+8+100.最後一個乙太網crc從來都不算進來的,因為內核已經判斷過了,對程序來說沒有任何意義了.
能: 接收發往本地mac的數據幀
能: 接收從本機發送出去的數據幀(第3個參數需要設置為ETH_P_ALL)
能: 接收非發往本地mac的數據幀(網卡需要設置為promisc混雜模式)
協議類型一共有四個
ETH_P_IP 0x800 只接收發往本機mac的ip類型的數據幀
ETH_P_ARP 0x806 只接受發往本機mac的arp類型的數據幀
ETH_P_RARP 0x8035 只接受發往本機mac的rarp類型的數據幀
ETH_P_ALL 0x3 接收發往本機mac的所有類型ip arp rarp的數據幀, 接收從本機發出的所有類型的數據幀.(混雜模式打開的情況下,會接收到非發往本地mac的數據幀)
發送的時候需要自己組織整個乙太網數據幀。所有相關的地址使用struct sockaddr_ll 而不是struct sockaddr_in(因為協議簇是PF_PACKET不是AF_INET了),比如發送給某個機器,對方的地址需要使用struct sockaddr_ll.

示例代碼

......
int sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); // 創建Socket
struct sockaddr_ll sll; // 注意結構體是sockaddr_ll
memset( &sll, 0, sizeof(sll) );
sll.sll_family = AF_PACKET;
struct ifreq ifstruct;
strcpy(ifstruct.ifr_name, "eth0");
ioctl(sockfd, SIOCGIFINDEX, &ifstruct); //控制I/O設備
sll.sll_ifindex = ifstruct.ifr_ifindex;
sll.sll_protocol = htons(ETH_P_ALL);
if(bind(fd, (struct sockaddr *) &sll, sizeof(sll)) == -1 ) { //在這裡當然仍然需要綁定的
perror("bind()");
......