我正在尝试使用原始套接字创建一个应用程序来监视网络流量,但我似乎只从计算机接收和发送正在处理的数据包。我无法找出其中的问题,但是当我检查时配置发现我没有数据通过我的enps20,而是仅通过wlp5s0,但是在我的代码中,我假设它是一个以太网协议,这是问题吗?如果是,我应该检查哪种协议以检查wlp5s0?
void error(int n,char* msg)
{
if(n==-1)
{
perror(msg);
exit(0);
}
}
void eth_hdr(struct ethhdr *eth)
{
printf("Ethernet Header : \n");
printf("Source MAC:%.2x.%.2x.%.2x.%.2x.%.2x%.2x\t",eth->h_source[0],eth->h_source[1],eth->h_source[2],eth->h_source[3],eth->h_source[4],eth->h_source[5]);
printf("Dest. MAC:%.2x.%.2x.%.2x.%.2x.%.2x%.2x\t",eth->h_dest[0],eth->h_dest[1],eth->h_dest[2],eth->h_dest[3],eth->h_dest[4],eth->h_dest[5]);
printf("Proto:%d\n",eth->h_proto);
}
void ip_hdr(struct iphdr *iph)
{
char address[INET6_ADDRSTRLEN];
struct sockaddr_in source,destination;
printf("IP Header : \n");
printf("%x\t",iph->version);
printf("%x\t",iph->protocol);
source.sin_addr.s_addr=iph->saddr;
destination.sin_addr.s_addr=iph->daddr;
inet_ntop(AF_INET,&source.sin_addr,address,INET_ADDRSTRLEN);
printf("Source Addr:%s\t",address);
inet_ntop(AF_INET,&destination.sin_addr,address,INET_ADDRSTRLEN);
printf("Destination Address:%s\n",address);
}
void udp_display(struct udphdr *udp)
{
struct sockaddr_in source,destination;
printf("UDP Header :\n");
printf("Source Port:%d\t",ntohs(udp->uh_sport));
printf("Destination Port:%d\t",ntohs(udp->uh_dport));
char address[INET6_ADDRSTRLEN];
source.sin_addr.s_addr=udp->source;
destination.sin_addr.s_addr=udp->dest;
inet_ntop(AF_INET,&source.sin_addr,address,INET_ADDRSTRLEN);
printf("Source Addr:%s\t",address);
inet_ntop(AF_INET,&destination.sin_addr,address,INET_ADDRSTRLEN);
printf("Destination Address:%s\n",address);
}
void tcp_display(struct tcphdr *tcp)
{
struct sockaddr_in source,destination;
printf("TCP Header :\n");
printf("Source Port:%d\t",ntohs(tcp->th_sport));
printf("Destination Port:%d\t",ntohs(tcp->th_dport));
char address[INET6_ADDRSTRLEN];
source.sin_addr.s_addr=tcp->source;
destination.sin_addr.s_addr=tcp->dest;
inet_ntop(AF_INET,&source.sin_addr,address,INET_ADDRSTRLEN);
printf("Source Addr:%s\t",address);
inet_ntop(AF_INET,&destination.sin_addr,address,INET_ADDRSTRLEN);
printf("Destination Address:%s\n",address);
}
int main()
{
int sockfd,n,on=1,iphdrlen;
struct ethhdr *eth;
struct iphdr *iph;
struct tcphdr *tcp;
struct udphdr *udp;
struct sockaddr addr,addr1;
struct sockaddr_ll address;
struct ifreq ifr;
socklen_t len;
unsigned char *buffer=(unsigned char*)malloc(65536);
unsigned char *data=(unsigned char*)malloc(65536);
memset(buffer,0,65536);
memset(&addr,0,sizeof(struct sockaddr));
memset(&addr1,0,sizeof(struct sockaddr));
memset(&address,0,sizeof(struct sockaddr_ll));
memset(&ifr,0,sizeof(struct ifreq));
sockfd=socket(AF_PACKET,SOCK_RAW,htons(ETH_P_ALL));
error(sockfd,"Error in creating a socket");
char *opt="wlp5s0";
setsockopt(sockfd,SOL_SOCKET,SO_BINDTODEVICE,opt,len);
strncpy(ifr.ifr_name,opt,sizeof(ifr.ifr_name));
n=ioctl(sockfd,SIOGIFINDEX,&ifr);
error(n,"Trouble in getting the Index information");
address.sll_family=AF_PACKET;
address.sll_ifindex=ifr.ifr_ifindex;
address.sll_protocol=htons(ETH_P_ALL);
n=bind(sockfd,(struct sockaddr*)&address,sizeof(struct sockaddr_ll));
error(n,"There has been a problem in binding with that interface");
while (1)
{
n=recvfrom(sockfd,buffer,sizeof(buffer),0,&addr,&len);
error(n,"There has been a problem recieving the data");
eth=(struct ethhdr*)&buffer;
eth_hdr(eth);
iph=(struct iphdr*)(buffer+sizeof(struct ethhdr));
ip_hdr(iph);
iphdrlen=(iph->ihl)*4;
if(iph->protocol==6)
{
tcp=(struct tcphdr*)(buffer+sizeof(struct ethhdr)+iphdrlen);
tcp_display(tcp);
data=(buffer+sizeof(struct ethhdr)+iphdrlen+sizeof(struct udphdr));
}
else if(iph->protocol==17)
{
udp=(struct udphdr*)(buffer+sizeof(struct ethhdr)+iphdrlen);
udp_display(udp);
// data=(buffer+sizeof(struct ethhdr)+iphdrlen+sizeof(struct udphdr));
}
}
return 0;
}
答案 0 :(得分:0)
注意:我可以在问题提供的程序中看到至少两个错误。
n=(int)recvfrom(sockfd,buffer,65536/*sizeof(buffer)*/,0,&addr,&len);
sizeof(buffer)
是指针的大小,而不是分配的数量。
eth=(struct ethhdr*)/*&*/buffer;
&
使eth
将变量buffer
本身视为存储;实际存储位置是变量指向的位置。
在提到的问题中,关于被监听的接口存在一种混乱,我在这里提供一种选择接口的方法。
很久以前,我曾经以混杂模式在特定的网络接口上打开一个数据包套接字,如下所示:
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/ether.h>
#include <netinet/in.h>
#include <net/if.h>
#include <netpacket/packet.h>
const char * name="eth0";
//---- Create socket ----
int fd=socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ALL));
if(fd==-1)
{ perror("socket"); return -1; }
//---- Find interface index ----
struct ifreq ifr;
memset(&ifr,0,sizeof(struct ifreq));
strncpy(ifr.ifr_name,name,sizeof(ifr.ifr_name));
if(ioctl(fd,SIOCGIFINDEX,&ifr)==-1)
{ perror("ioctl SIOCGIFINDEX"); close(fd); return -1; }
int index=ifr.ifr_ifindex;
//---- Bind socket to interface ----
struct sockaddr_ll addr;
memset(&addr,0,sizeof(struct sockaddr_ll));
addr.sll_family=AF_PACKET;
addr.sll_ifindex=index;
addr.sll_protocol=htons(ETH_P_ALL);
if(bind(fd,(struct sockaddr *)&addr,sizeof(struct sockaddr_ll))==-1)
{ perror("bind"); close(fd); return -1; }
//---- Determine MTU ----
memset(&ifr,0,sizeof(struct ifreq));
strncpy(ifr.ifr_name,name,sizeof(ifr.ifr_name));
if(ioctl(fd,SIOCGIFMTU,&ifr)==-1)
{ perror("ioctl SIOCGIFMTU"); close(fd); return -1; }
unsigned int mtu=ifr.ifr_mtu;
//---- Switch to promiscuous mode ----
struct packet_mreq mr;
memset(&mr,0,sizeof(struct packet_mreq));
mr.mr_ifindex=index;
mr.mr_type=PACKET_MR_PROMISC;
if(setsockopt(fd,SOL_PACKET,PACKET_ADD_MEMBERSHIP,
&mr,sizeof(struct packet_mreq))==-1)
{ perror("setsockopt PACKET_MR_PROMISC"); close(fd); return -1; }
对不起,它有点长,但是每个部分的注释都应该可以自我解释。
ioctl()
用于许多目的;这是有关Linux网络设备的文档:
http://man7.org/linux/man-pages/man7/netdevice.7.html
将数据包套接字绑定到接口时,我们必须为bind()
提供一个地址结构,以告知套接字将绑定到哪个网络接口。
这种特定的结构类型是struct sockaddr_ll
(与ipv4套接字使用struct sockaddr_in
的方式相同)和相关字段if sll_ifindex
(整数索引)。
该索引由操作系统在枚举网络设备时给定;由于先前对ioctl(SIOCGIFINDEX)
的调用会根据接口名称(ifr_name
的{{1}}字段)对其进行检索,因此我们了解了它。