</pre>數據報式套接字(SOCK_DGRAM),僅限於UDP;<p></p><p>流式套接字(SOCK_STREAM),僅限於TCP;</p><p>TCP與UDP各自有獨立的port互不影響,沒一個進程可以使用多個port;</p><p></p><p>原始套接字(SOCK_RAW),它實現於系統核心.可以接收本機網卡上所有的數據幀(數據包),對於監聽網絡流量和分析網絡數據很有作用.開發人員可發送自己組裝的數據包到網絡上.原始套接字可以收發內核沒有處理的數據包 因此,要訪問其他協議發送的數據需要使用原始套接字(SOCK_RAW);</p><p></p><p>int socket(PF_PACKET, SOCK_RAW, protocol)功能:創建鏈路層的原始套接字</p><p><span style="font-size:12px;">protocol:指定可以接收或發送的數據包類型</span></p><p>ETH_P_IP:IPV4數據包ETH_P_ARP:ARP數據包ETH_P_ALL:任何協議類型的數據包;</p><p>例如:</p><p>成功返回套接字;</p><p>sock_raw_fd = socket(PF_PACKET,SOCK_RAW,htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL));</p><p>頭文件:</p><p>#include <sys/socket.h>#include <netinet/ether.h></p><p>使用原始套接字進行編程開發時,首先要對不同協議的數據包進行學習,需要手動對IP、TCP、UDP、ICMP等包頭進行組裝或者拆解。</p><p>組裝/拆解udp數據包流程:port來標記給哪個進程<img src="https://img-blog.csdn.net/20150822130901589?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" /></p><p></p><p></p><pre name="code" class="cpp">*
* =====================================================================================
*
* Filename:
*
* Description:
*
* Version: 1.0
* Created:
* Revision: none
* Compiler: gcc
*
* Author: Dr. moshui (no_water), [email protected]
* Organization:
*
* =====================================================================================
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/ether.h>
int main(int argc,char *argv[])
{
int i = 0;
unsigned char buf[1024] = "";
unsigned char type[10] = {1, 6, 17};//ICMP->1、TCP->6、UDP->17
char name[10][128] = {"ICMP", "TCP", "UDP"};
int sock_raw_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
while(1)
{
unsigned char src_mac[18] = "";
unsigned char dst_mac[18] = "";
unsigned char dst_ip[16] = "";
unsigned char src_ip[16] = "";
//獲取鏈路層的數據幀
recvfrom(sock_raw_fd, buf, sizeof(buf),0,NULL,NULL);
//從buf裏提取目的mac、源mac
sprintf(dst_mac,"%02x:%02x:%02x:%02x:%02x:%02x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
sprintf(src_mac,"%02x:%02x:%02x:%02x:%02x:%02x", buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]);
//判斷是否爲IP數據包
if(buf[12]==0x08 && buf[13]==0x00)
{
printf("______________IP數據報_______________\n");
printf("MAC:%s >> %s\n",src_mac,dst_mac);
//獲取源IP、目的IP
sprintf(src_ip,"%d:%d:%d:%d", buf[26], buf[27], buf[28], buf[29]);
sprintf(dst_ip,"%d:%d:%d:%d", buf[30], buf[31], buf[32], buf[33]);
printf("IP:%s >> %s\n",src_ip,dst_ip);
for(i=0;i<10;i++)
{
if(buf[23] == type[i])
{
printf("協議類別:%s\n",name[i]);
}
}
}//判斷是否爲ARP數據包
else if(buf[12]==0x08 && buf[13]==0x06)
{
printf("______________ARP數據報_______________\n");
printf("MAC:%s >> %s\n",src_mac,dst_mac);
//獲取源IP、目的IP
sprintf(src_ip,"%d:%d:%d:%d", buf[28], buf[29], buf[30], buf[31]);
sprintf(dst_ip,"%d:%d:%d:%d", buf[38], buf[39], buf[40], buf[41]);
printf("IP:%s >> %s\n",src_ip,dst_ip);
}//判斷是否爲RARP數據包
else if(buf[12]==0x80 && buf[13]==0x35)
{
printf("______________RARP數據報_______________\n");
printf("MAC:%s>>%s\n",src_mac,dst_mac);
//獲取源IP、目的IP(RARP報文格式與ARP報文格式一樣)
sprintf(src_ip,"%d:%d:%d:%d", buf[28], buf[29], buf[30], buf[31]);
sprintf(dst_ip,"%d:%d:%d:%d", buf[38], buf[39], buf[40], buf[41]);
printf("IP:%s>>%s\n",src_ip,dst_ip);
}
}
return 0;
}
設置混雜模式:ifconfig eth0 promisc
取消混雜模式:ifconfig eth0 -promisc
用sendto發送原始套接字數據:
sendto(sock_raw_fd, msg, msg_len, 0,(struct sockaddr*)&sll, sizeof(sll));
sock_raw_fd:原始套接字
msg:發送的消息(封裝好的協議數據)
sll:本機網絡接口,指發送的數據應該從本機的哪個網卡出去,而不是以前的目的地址
本機網絡接口
struct sockaddr_ll sll;
#include <netpacket/packet.h>
通過ioctl來獲取網絡接口地址
int ioctl(int fd, int request,void *)
#include <sys/ioctl.h>
獲取到當前網段中所有機器的MAC地址:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <net/if.h> //struct ifreq
#include <sys/ioctl.h> //ioctl、SIOCGIFADDR
#include <sys/socket.h>
#include <netinet/ether.h> //ETH_P_ALL
#include <netpacket/packet.h> //struct sockaddr_ll
#include <pthread.h>
#include <netinet/in.h>
void *send_arp_ask(void *arg);
int main(int argc,char *argv[])
{
//1.創建通信用的原始套接字
int sock_raw_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
//2.創建發送線程
pthread_t tid;
pthread_create(&tid, NULL, (void *)send_arp_ask, (void *)sock_raw_fd);
while(1)
{
//3.接收對方的ARP應答
unsigned char recv_msg[1024] = "";
recvfrom(sock_raw_fd, recv_msg, sizeof(recv_msg), 0, NULL, NULL);
if(recv_msg[21] == 2) //ARP應答
{
char resp_mac[18] = ""; //arp響應的MAC
char resp_ip[16] = ""; //arp響應的IP
sprintf(resp_mac, "%02x:%02x:%02x:%02x:%02x:%02x", \
recv_msg[22],recv_msg[23],recv_msg[24],recv_msg[25],recv_msg[26],recv_msg[27]);
sprintf(resp_ip, "%d.%d.%d.%d", recv_msg[28], recv_msg[29], recv_msg[30], recv_msg[31]);
printf("IP:%s - MAC:%s\n",resp_ip, resp_mac);
}
}
return 0;
}
void *send_arp_ask(void *arg)
{
int i = 0;
int sock_raw_fd = (int)arg;
//1.根據各種協議首部格式構建發送數據報
unsigned char send_msg[1024] = {
//--------------組MAC--------14------
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, //dst_mac: FF:FF:FF:FF:FF:FF
0x00, 0x0c, 0x29, 0x75, 0xa6, 0x51, //src_mac: 00:0c:29:75:a6:51
0x08, 0x06, //類型:0x0806 ARP協議
//--------------組ARP--------28-----
0x00, 0x01, 0x08, 0x00, //硬件類型1(以太網地址),協議類型0x0800(IP)
0x06, 0x04, 0x00, 0x01, //硬件、協議地址分別是6、4,op:(1:arp請求,2:arp應答)
0x00, 0x0c, 0x29, 0x75, 0xa6, 0x51, //發送端的MAC地址
172, 20, 226, 12, //發送端的IP地址
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //目的MAC地址(由於要獲取對方的MAC,所以目的MAC置零)
172, 20, 226, 11 //目的IP地址
};
//2.數據初始化
struct sockaddr_ll sll; //原始套接字地址結構
struct ifreq ethreq; //網絡接口地址
strncpy(ethreq.ifr_name, "eth0", IFNAMSIZ); //指定網卡名稱
//3.將網絡接口賦值給原始套接字地址結構
ioctl(sock_raw_fd, SIOCGIFINDEX, (char *)ðreq);
bzero(&sll, sizeof(sll));
sll.sll_ifindex = ethreq.ifr_ifindex;
//4.本地機的IP
if(!(ioctl(sock_raw_fd, SIOCGIFADDR, (char *)ðreq)))
{
int num = ntohl(((struct sockaddr_in*) (ðreq.ifr_addr))->sin_addr.s_addr);
for(i=0; i<4; i++)
{
send_msg[31-i] = num>>8*i & 0xff; //將發送端的IP地址組包
}
}
//5.獲取本地機(eth0)的MAC
if (!(ioctl(sock_raw_fd, SIOCGIFHWADDR, (char *) ðreq)))
{
for(i=0; i<6; i++)
{
//將src_mac、發送端的MAC地址組包
send_msg[22+i] = send_msg[6+i] = (unsigned char) ethreq.ifr_hwaddr.sa_data[i];
}
}
while(1)
{
int i = 0;
int num[4] = {0};
unsigned char input_buf[1024] = "";
//6.獲取所要掃描的網段(172.20.226.0)
printf("input_dst_Network:172.20.226.0\n");
fgets(input_buf, sizeof(input_buf), stdin);
sscanf(input_buf, "%d.%d.%d.", &num[0], &num[1], &num[2]//目的IP地址
);
//7.將鍵盤輸入的信息組包
for(i=0;i<4;i++)
send_msg[38+i] = num[i];//將目的IP地址組包
//8.給1~254的IP發送ARP請求
for(i=1; i<255; i++)
{
send_msg[41] = i;
int len = sendto(sock_raw_fd, send_msg, 42, 0 , (struct sockaddr *)&sll, sizeof(sll));
if(len == -1)
{
perror("sendto");
}
}
sleep(1);
}