本文主要是介绍A Guide to Using Raw Sockets(翻译),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
在本教程中,让我们来看一看,原始套接字如何被用来绕过传统的TCP/IP协议栈,接收数据包,然后把那些数据包发送给特定的用户程序。
如果你不具备Linux内核相关的知识,但是对网络报文的内容感兴趣,那么原始套接字就是你所需要的。一个原始套接字是用来接收原始报文的。这意味着在以太层接收到的报文将会直接传递给原始套接字。准确地说,一个原始套接字绕过通常的TCP/IP处理过程,将报文发送给特定的用户程序。
原始套接字 vs 其他套接字
其他套接字,例如字节流套接字和数据报套接字,从传输层接收数据。这些数据不包含头部(header),只包含净荷(payload)。这意味着,没有关于源IP地址和MAC地址的信息。运行在同一台机器或不同机器上的程序在通信时,只能交换数据。
原始套接字的用途是完全不同的。原始套接字允许程序直接访问更低层的协议。这意味着原始套接字接收未提取(un-extracted)的报文。与字节流/数据报套接字不同,没有必要给一个原始套接字提供端口和IP地址。
网络报文与报文嗅探器
当一个应用程序向网络中发送数据时,数据会被许多的网络层次处理。在发送数据之前,它会被网络层次的各种头部包裹。包含所有的信息,例如原地址和目的地址,的被包裹的数据,被称为网络报文。根据以太网协议,有许多不同种类的网络报文,例如IP报文,Xerox PUP报文,Ethernet Loopback报文等。在Linux中,可以再if_ether.h中找到所有的协议。
当我们连接到因特网时,我们接收网络报文,我们的机器提取所有的网络层头部,将数据发送给特定的的程序。例如,当我们在浏览器中输入www.google.com时,我们收到来自Google的报文,我们的机器提取所有的头部,将数据传送给浏览器。
默认情况下,一台机器只会接受目的地之是它自己的报文,这种模式成为非混杂(Non-promiscuous)模式。但是,如果我们想要接收所有的报文,我们就必须切换到混杂(Promiscuous)模式。通过使用ioctl,我们可以切换到混杂模式。
如果我们对不同网络层次头部的内容或者结构感兴趣,我们可以借助报文嗅探器来访问这些信息。在Linux中有许多可用的报文嗅探器,例如Wireshark、tcpdump。
一个使用原始套接字的报文嗅探器
要开发一个报文嗅探器,首先要打开一个原始套接字。只有effective user ID是0或者具有CAP_NET_RAW能力的进程才被允许打开原始套接字。
打开一个原始套接字
要打开一个套接字,要知道三样东西
- 协议族
- 类型
- 协议
对于一个原始套接字,协议族是AF_PACKET,协议类型是SOCK_RAW,协议请参看if_ether.h头文件。要接受所有报文,可以将协议设置为宏ETH_P_ALL;要接受所有IP报文,可以将协议设置为宏ETH_P_IP。
int sock_r;
sock_r = socket(AP_PACKET,SOCK_RAW,htons(ETH_P_ALL));
if(sock_r < 0)
{printf("error in socket\n");return -1;
}
/* Note: run this program as root user* Author:Subodh Saxena */
#include<stdio.h>
#include<malloc.h>
#include<string.h>
#include<signal.h>
#include<stdbool.h>
#include<sys/socket.h>
#include<sys/types.h>#include<linux/if_packet.h>
#include<netinet/in.h>
#include<netinet/if_ether.h> // for ethernet header
#include<netinet/ip.h> // for ip header
#include<netinet/udp.h> // for udp header
#include<netinet/tcp.h>
#include<arpa/inet.h> // to avoid warning at inet_ntoaFILE* log_txt;
int total,tcp,udp,icmp,igmp,other,iphdrlen;struct sockaddr saddr;
struct sockaddr_in source,dest;void ethernet_header(unsigned char* buffer,int buflen)
{struct ethhdr *eth = (struct ethhdr *)(buffer);fprintf(log_txt,"\nEthernet Header\n");fprintf(log_txt,"\t|-Source Address : %.2X-%.2X-%.2X-%.2X-%.2X-%.2X\n",eth->h_source[0],eth->h_source[1],eth->h_source[2],eth->h_source[3],eth->h_source[4],eth->h_source[5]);fprintf(log_txt,"\t|-Destination Address : %.2X-%.2X-%.2X-%.2X-%.2X-%.2X\n",eth->h_dest[0],eth->h_dest[1],eth->h_dest[2],eth->h_dest[3],eth->h_dest[4],eth->h_dest[5]);fprintf(log_txt,"\t|-Protocol : %d\n",eth->h_proto);}void ip_header(unsigned char* buffer,int buflen)
{struct iphdr *ip = (struct iphdr*)(buffer + sizeof(struct ethhdr));iphdrlen =ip->ihl*4;memset(&source, 0, sizeof(source));source.sin_addr.s_addr = ip->saddr; memset(&dest, 0, sizeof(dest));dest.sin_addr.s_addr = ip->daddr; fprintf(log_txt , "\nIP Header\n");fprintf(log_txt , "\t|-Version : %d\n",(unsigned int)ip->version);fprintf(log_txt , "\t|-Internet Header Length : %d DWORDS or %d Bytes\n",(unsigned int)ip->ihl,((unsigned int)(ip->ihl))*4);fprintf(log_txt , "\t|-Type Of Service : %d\n",(unsigned int)ip->tos);fprintf(log_txt , "\t|-Total Length : %d Bytes\n",ntohs(ip->tot_len));fprintf(log_txt , "\t|-Identification : %d\n",ntohs(ip->id));fprintf(log_txt , "\t|-Time To Live : %d\n",(unsigned int)ip->ttl);fprintf(log_txt , "\t|-Protocol : %d\n",(unsigned int)ip->protocol);fprintf(log_txt , "\t|-Header Checksum : %d\n",ntohs(ip->check));fprintf(log_txt , "\t|-Source IP : %s\n", inet_ntoa(source.sin_addr));fprintf(log_txt , "\t|-Destination IP : %s\n",inet_ntoa(dest.sin_addr));
}void payload(unsigned char* buffer,int buflen)
{int i=0;unsigned char * data = (buffer + iphdrlen + sizeof(struct ethhdr) + sizeof(struct udphdr));fprintf(log_txt,"\nData\n");int remaining_data = buflen - (iphdrlen + sizeof(struct ethhdr) + sizeof(struct udphdr));for(i=0;i<remaining_data;i++){if(i!=0 && i%16==0)fprintf(log_txt,"\n");fprintf(log_txt," %.2X ",data[i]);}fprintf(log_txt,"\n");}void tcp_header(unsigned char* buffer,int buflen)
{fprintf(log_txt,"\n*************************TCP Packet******************************");ethernet_header(buffer,buflen);ip_header(buffer,buflen);struct tcphdr *tcp = (struct tcphdr*)(buffer + iphdrlen + sizeof(struct ethhdr));fprintf(log_txt , "\nTCP Header\n");fprintf(log_txt , "\t|-Source Port : %u\n",ntohs(tcp->source));fprintf(log_txt , "\t|-Destination Port : %u\n",ntohs(tcp->dest));fprintf(log_txt , "\t|-Sequence Number : %u\n",ntohl(tcp->seq));fprintf(log_txt , "\t|-Acknowledge Number : %u\n",ntohl(tcp->ack_seq));fprintf(log_txt , "\t|-Header Length : %d DWORDS or %d BYTES\n" ,(unsigned int)tcp->doff,(unsigned int)tcp->doff*4);fprintf(log_txt , "\t|----------Flags-----------\n");fprintf(log_txt , "\t\t|-Urgent Flag : %d\n",(unsigned int)tcp->urg);fprintf(log_txt , "\t\t|-Acknowledgement Flag : %d\n",(unsigned int)tcp->ack);fprintf(log_txt , "\t\t|-Push Flag : %d\n",(unsigned int)tcp->psh);fprintf(log_txt , "\t\t|-Reset Flag : %d\n",(unsigned int)tcp->rst);fprintf(log_txt , "\t\t|-Synchronise Flag : %d\n",(unsigned int)tcp->syn);fprintf(log_txt , "\t\t|-Finish Flag : %d\n",(unsigned int)tcp->fin);fprintf(log_txt , "\t|-Window size : %d\n",ntohs(tcp->window));fprintf(log_txt , "\t|-Checksum : %d\n",ntohs(tcp->check));fprintf(log_txt , "\t|-Urgent Pointer : %d\n",tcp->urg_ptr);payload(buffer,buflen);fprintf(log_txt,"*****************************************************************\n\n\n");
}void udp_header(unsigned char* buffer, int buflen)
{fprintf(log_txt,"\n*************************UDP Packet******************************");ethernet_header(buffer,buflen);ip_header(buffer,buflen);fprintf(log_txt,"\nUDP Header\n");struct udphdr *udp = (struct udphdr*)(buffer + iphdrlen + sizeof(struct ethhdr));fprintf(log_txt , "\t|-Source Port : %d\n" , ntohs(udp->source));fprintf(log_txt , "\t|-Destination Port : %d\n" , ntohs(udp->dest));fprintf(log_txt , "\t|-UDP Length : %d\n" , ntohs(udp->len));fprintf(log_txt , "\t|-UDP Checksum : %d\n" , ntohs(udp->check));payload(buffer,buflen);fprintf(log_txt,"*****************************************************************\n\n\n");}void data_process(unsigned char* buffer,int buflen)
{struct iphdr *ip = (struct iphdr*)(buffer + sizeof (struct ethhdr));++total;/* we will se UDP Protocol only*/ switch (ip->protocol) //see /etc/protocols file {case 6:++tcp;tcp_header(buffer,buflen);break;case 17:++udp;udp_header(buffer,buflen);break;default:++other;}printf("TCP: %d UDP: %d Other: %d Toatl: %d \r",tcp,udp,other,total);}int main()
{int sock_r,saddr_len,buflen;unsigned char* buffer = (unsigned char *)malloc(65536); memset(buffer,0,65536);log_txt=fopen("log.txt","w");if(!log_txt){printf("unable to open log.txt\n");return -1;}printf("starting .... \n");sock_r=socket(AF_PACKET,SOCK_RAW,htons(ETH_P_ALL)); if(sock_r<0){printf("error in socket\n");return -1;}while(1){saddr_len=sizeof saddr;buflen=recvfrom(sock_r,buffer,65536,0,&saddr,(socklen_t *)&saddr_len);if(buflen<0){printf("error in reading recvfrom function\n");return -1;}fflush(log_txt);data_process(buffer,buflen);}close(sock_r);// use signals to close socket printf("DONE!!!!\n");}
/* Note: run this program as root user* Author:Subodh Saxena */
#include<stdio.h>
#include<string.h>
#include<malloc.h>
#include<errno.h>#include<sys/socket.h>
#include<sys/types.h>
#include<sys/ioctl.h>#include<net/if.h>
#include<netinet/in.h>
#include<netinet/ip.h>
#include<netinet/if_ether.h>
#include<netinet/udp.h>#include<linux/if_packet.h>#include<arpa/inet.h>
struct ifreq ifreq_c,ifreq_i,ifreq_ip; /// for each ioctl keep diffrent ifreq structure otherwise error may come in sending(sendto )
int sock_raw;
unsigned char *sendbuff;#define DESTMAC0 0xd0#define DESTMAC1 0x67#define DESTMAC2 0xe5#define DESTMAC3 0x12#define DESTMAC4 0x6f#define DESTMAC5 0x8f#define destination_ip 10.240.253.10int total_len=0,send_len;void get_eth_index()
{memset(&ifreq_i,0,sizeof(ifreq_i));strncpy(ifreq_i.ifr_name,"wlan0",IFNAMSIZ-1);if((ioctl(sock_raw,SIOCGIFINDEX,&ifreq_i))<0)printf("error in index ioctl reading");printf("index=%d\n",ifreq_i.ifr_ifindex);}void get_mac()
{memset(&ifreq_c,0,sizeof(ifreq_c));strncpy(ifreq_c.ifr_name,"wlan0",IFNAMSIZ-1);if((ioctl(sock_raw,SIOCGIFHWADDR,&ifreq_c))<0)printf("error in SIOCGIFHWADDR ioctl reading");printf("Mac= %.2X-%.2X-%.2X-%.2X-%.2X-%.2X\n",(unsigned char)(ifreq_c.ifr_hwaddr.sa_data[0]),(unsigned char)(ifreq_c.ifr_hwaddr.sa_data[1]),(unsigned char)(ifreq_c.ifr_hwaddr.sa_data[2]),(unsigned char)(ifreq_c.ifr_hwaddr.sa_data[3]),(unsigned char)(ifreq_c.ifr_hwaddr.sa_data[4]),(unsigned char)(ifreq_c.ifr_hwaddr.sa_data[5]));printf("ethernet packaging start ... \n");struct ethhdr *eth = (struct ethhdr *)(sendbuff);eth->h_source[0] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[0]);eth->h_source[1] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[1]);eth->h_source[2] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[2]);eth->h_source[3] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[3]);eth->h_source[4] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[4]);eth->h_source[5] = (unsigned char)(ifreq_c.ifr_hwaddr.sa_data[5]);eth->h_dest[0] = DESTMAC0;eth->h_dest[1] = DESTMAC1;eth->h_dest[2] = DESTMAC2;eth->h_dest[3] = DESTMAC3;eth->h_dest[4] = DESTMAC4;eth->h_dest[5] = DESTMAC5;eth->h_proto = htons(ETH_P_IP); //0x800printf("ethernet packaging done.\n");total_len+=sizeof(struct ethhdr);}void get_data()
{sendbuff[total_len++] = 0xAA;sendbuff[total_len++] = 0xBB;sendbuff[total_len++] = 0xCC;sendbuff[total_len++] = 0xDD;sendbuff[total_len++] = 0xEE;}void get_udp()
{struct udphdr *uh = (struct udphdr *)(sendbuff + sizeof(struct iphdr) + sizeof(struct ethhdr));uh->source = htons(23451);uh->dest = htons(23452);uh->check = 0;total_len+= sizeof(struct udphdr);get_data();uh->len = htons((total_len - sizeof(struct iphdr) - sizeof(struct ethhdr)));}unsigned short checksum(unsigned short* buff, int _16bitword)
{unsigned long sum;for(sum=0;_16bitword>0;_16bitword--)sum+=htons(*(buff)++);do{sum = ((sum >> 16) + (sum & 0xFFFF));}while(sum & 0xFFFF0000);return (~sum);}void get_ip()
{memset(&ifreq_ip,0,sizeof(ifreq_ip));strncpy(ifreq_ip.ifr_name,"wlan0",IFNAMSIZ-1);if(ioctl(sock_raw,SIOCGIFADDR,&ifreq_ip)<0){printf("error in SIOCGIFADDR \n");}printf("%s\n",inet_ntoa((((struct sockaddr_in*)&(ifreq_ip.ifr_addr))->sin_addr)));/****** ORint i;for(i=0;i<14;i++)printf("%d\n",(unsigned char)ifreq_ip.ifr_addr.sa_data[i]); ******/struct iphdr *iph = (struct iphdr*)(sendbuff + sizeof(struct ethhdr));iph->ihl = 5;iph->version = 4;iph->tos = 16;iph->id = htons(10201);iph->ttl = 64;iph->protocol = 17;iph->saddr = inet_addr(inet_ntoa((((struct sockaddr_in *)&(ifreq_ip.ifr_addr))->sin_addr)));iph->daddr = inet_addr("destination_ip"); // put destination IP addresstotal_len += sizeof(struct iphdr); get_udp();iph->tot_len = htons(total_len - sizeof(struct ethhdr));iph->check = htons(checksum((unsigned short*)(sendbuff + sizeof(struct ethhdr)), (sizeof(struct iphdr)/2)));}int main()
{sock_raw=socket(AF_PACKET,SOCK_RAW,IPPROTO_RAW);if(sock_raw == -1)printf("error in socket");sendbuff=(unsigned char*)malloc(64); // increase in case of large data.Here data is --> AA BB CC DD EEmemset(sendbuff,0,64);get_eth_index(); // interface numberget_mac();get_ip();struct sockaddr_ll sadr_ll;sadr_ll.sll_ifindex = ifreq_i.ifr_ifindex;sadr_ll.sll_halen = ETH_ALEN;sadr_ll.sll_addr[0] = DESTMAC0;sadr_ll.sll_addr[1] = DESTMAC1;sadr_ll.sll_addr[2] = DESTMAC2;sadr_ll.sll_addr[3] = DESTMAC3;sadr_ll.sll_addr[4] = DESTMAC4;sadr_ll.sll_addr[5] = DESTMAC5;printf("sending...\n");while(1){send_len = sendto(sock_raw,sendbuff,64,0,(const struct sockaddr*)&sadr_ll,sizeof(struct sockaddr_ll));if(send_len<0){printf("error in sending....sendlen=%d....errno=%d\n",send_len,errno);return -1;}}}
https://opensourceforu.com/2015/03/a-guide-to-using-raw-sockets/
这篇关于A Guide to Using Raw Sockets(翻译)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!