数据链路层的访问,高级货哦
SOCK_PACKET类型,数据从网卡的协议栈交给用户
建立一个SOCK_PACKET类型如下:
socket(AF_INET,SOCK_PACKET,htons(0x0003));
设置套接口以捕获链路帧的编程方法
#include
#include//ioctl命令
#include//ethhdr结构
#include//ifreq结构
#include//in_addr结构
#include//iphdr结构
#include//udphdr结构
#include//tcp结构
创建SOCK_PACKET类型套接字的方法
int
fd;
fd=socket(AF_INET,SOCK_PACKET,htons(0x003));
对网卡进行设置:
char
*errname ="eth0";//对网卡eth0进行混杂设置
struct
ifreq ifr;//网卡接口结构
strcpy(ifr.ifr_name,ethname);
//eth0写入ifr结构的一个字段中
i=ioctl(fd,SIOCGIFFLAGS,&ifr);//获取eth0的标志位值
if(i<0)
{
close(fd);
perror("can't
get flags\n");
return
-1;
}
ifr.ifr_flags|=IFF_PROMISC;//保留原来设置的情况下,在标志中加入混杂模式
i=ioctl(fd,SIOCSIFFLAGS,&ifr);
if(i<0)
{
perror("promiscuous
set error\n");
return
-2;
}
从套接口读取链路帧的编程方法
#define
ETH_ALEN 6 //以太网地址,即MAC地址,6字节
#define
ETH_HLEN 14 //以太网头部的总长度
#define
ETH_ZLEN 60 //不含CRC校验的数据最小长度
#define
ETH_DATA_LEN 1500 //帧内数据的最大长度
#define
ETH_FRAME_LEN 1514 //不含CRC校验和的最大以太网数据长度
strcut
ethhdr{
unsigned
char h_dest[ETH_ALEN];//目的以太网地址
unsigned
char h_source[ETH_ALEN]; //源以太网地址
__be16
h_proto; //包类型
};
linux/if_ether.h包含的定义:
例子:
char
ef[ETH_FRAME_LEN];
struct
ethhdr *p_ethhdr; //以太网头部指针
int
n;
p_ethhdr=(struct
ethhdr *)ef; //使p_ethhdr指向以太网帧的帧头
n=read(fd,ef,ETH_FRAME_LEN);
//n返回实际捕获的以太帧的帧长
printf("dest
MAC:";
for(i=0;i
printf("%02x-",p_ethhdr->h_dest[i]);
}
printf("%02x\n",p_ethhdr->d_dest[ETH_ALEN-1]);
printf("source
MAC:");
for(int
i=0;i
{
printf("%02x-\n",p_ethhdr->d_source[i]);
}
printf("%02x",p_ethhdr->d_source[ETH_ALEN-1])
printf("protocol:0x%04x",ntohs(p_ethhdr->h_proto));
ARP协议数据结构:
以太网头部目的硬件地址
源硬件地址
帧类型
6
6 2
ARP请求应答硬件类型
协议类型
硬件地址长度
协议地址长度
操作方式
发送方硬件地址
发送方IP地址
接收方硬件地址
接收方IP地址
struct
arphdr
{
__be16
ar_hrd;//硬件类型
__be16
ar_pro;//协议类型
unsigned
char ar_hln; //硬件地址长度
unsigned
cahr ar_hln; //协议地址长度
__be16
ar_op;//ARP操作码
};
成员
成员含义
值
值含义
ar_hrd
硬件类型
1
硬件地址为以太网接口
ar_pro
协议类型
0x0800
高层协议为IP协议
ar_hln
硬件地址长度
6
6字节,即MAC地址48位
ar_pln
协议地址长度
4
IP协议地址长度为32位
ar_op
ARP操作码
1
ARP请求