server.c
===============================================================================
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/if_ether.h>
#include <net/if_arp.h>
#include <net/if.h>
#include <net/ethernet.h>
#include <netpacket/packet.h>
#include <netinet/ether.h>
#include <string.h>
#include <pthread.h>
void print_hex(unsigned char *buffer, int len){
int i;
printf("******************start code**********************************\n");
for(i = 1; i <= len; i++){
printf("0x%02X ",buffer[i-1]);
if(i % 16 == 0){
printf("\n");
}
}
printf("\n");
printf("********************end code************************************\n");
}
int main()
{
unsigned char buf[2048];
int sock_raw_fd ;
sock_raw_fd = socket(PF_PACKET,SOCK_RAW,htons(0x3001));//ETH_P_ALL));
printf("sock_raw_fd = %d\n",sock_raw_fd);
int nread;
while(1)
{
nread = recvfrom(sock_raw_fd,buf,2048,0,NULL,NULL);
printf("nread = %d\n",nread);
print_hex(buf,nread);
}
return 0;
}
//当socket函数的最后一个参数协议字段,填写ETH_P_ALL时,将收到所有类型的二层链路帧。
//比如这种情形,server运行在PC机上(ETH_P_ALL);client运行在同一台PC机上(0x3001),通过ens33网口向外发送自定义的二层链路帧,此时server能够接收到client的二层链路帧。
//server运行在PC机上(0x3001);client运行在同一台PC机上(0x3001),通过ens33网口向外发送自定义的二层链路帧,此时server不能接收到client的二层链路帧。
client.c
==============================================================================
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/if_ether.h>
#include <net/if_arp.h>
#include <net/if.h>
#include <net/ethernet.h>
#include <netpacket/packet.h>
#include <netinet/ether.h>
#include <string.h>
#include <pthread.h>
void print_hex(unsigned char *buffer, int len){
int i;
printf("******************start code**********************************\n");
for(i = 1; i <= len; i++){
printf("0x%02X ",buffer[i-1]);
if(i % 16 == 0){
printf("\n");
}
}
printf("\n");
printf("********************end code************************************\n");
}
int main()
{
//00:0c:29:de:a6:c5 目的MAC地址
//52:54:00:9b:38:7a 源MAC地址,这个可以随便填写,只关心目的MAC地址
unsigned char buf[128]={0x0,0x0c,0x29,0xde,0xa6,0xc5,0x52,0x54,0,0x9b,0x38,0x7a,0x30,0x1};
int sock_raw_fd ;
sock_raw_fd = socket(PF_PACKET,SOCK_RAW,htons(0x3001));
int nwrite;
short type = htons(0x3001);
memcpy(buf+12,&type,2);
//memset(buf,0x01,128);
struct sockaddr_ll sll; //原始套接字地址结构
struct ifreq ethreq; //网络接口地址
strncpy(ethreq.ifr_name, "ens33", IFNAMSIZ); //指定网卡名称
if(-1 == ioctl(sock_raw_fd, SIOCGIFINDEX, ðreq)) //获取网络接口
{
perror("ioctl");
close(sock_raw_fd);
exit(-1);
}
/*将网络接口赋值给原始套接字地址结构*/
bzero(&sll, sizeof(sll));
sll.sll_ifindex = ethreq.ifr_ifindex;
// 发送数据
int len = sendto(sock_raw_fd, buf, 14, 0 , (struct sockaddr *)&sll, sizeof(sll));
if(len == -1)
{
perror("sendto");
}
print_hex(buf,14);
printf("len = %d\n",len);
}
server和client运行在不同的机器下:
1、client的目的MAC地址填写正确(server和client都是0x3001),在server是否为混杂模式下都可以收到数据。
2、client的目的MAC地址填写错误(server和client都是0x3001),server必须在混杂模式下才能收到数据。
3、server(ETH_P_ALL);client(0x3001),通过ens33网口向外发送自定义的二层链路帧,在目的MAC地址正确的情况下,此时server(无论是否为混杂模式)能接收到client的二层链路帧。
4、server(ETH_P_ALL);client(0x3001),通过ens33网口向外发送自定义的二层链路帧,在目的MAC地址错误的情况下,此时server(混杂模式)能接收到client的二层链路帧;此时server(非混杂模式)不能接收到client的二层链路帧。
设置混杂模式: ifconfig ens33 promisc
清除混杂模式:ifconfig ens33 -promisc
注:
client发送大于等于14字节且小于60字节,server收到的都是60字节。大于60字节时,server收到的是client发送的实际字节数。