各种帧头及嗅探器一般步骤
我在这里写的第一篇文章。
许多人推荐这个网站,说很多高手在这里写博客,激扬文字。我还不是高手,但总有一天会是的。
以下是嗅探器的一般步骤和各种头结构:
建立直接从链路层读取数据的套接字:fd_1 = socket(PF_PACKET, SOCK_RAW, htons(0x0003));
设置网卡混杂模式:
struct ifreq ifr;
int i;
strcpy(ifr.ifr_name, adapt);
i = ioctl(fd_1, SIOCGIFFLAGS, &ifr);
if (i < 0){
perror("Can't get adapter flags");
return 0;
}
ifr.ifr_flags |= IFF_PROMISC;
i = ioctl(fd_1, SIOCSIFFLAGS, &ifr);
if (i < 0){
perror("Promiscuous mode set error");
return 0;
}
各种包头部长度宏定义:
#define ETH_H 14
#define PPP_H 8
#define IP_H 20
#define IP_MAX_H 60
#define IP6_H 40
#define ARP_H 24
#define TCP_H 20
#define UDP_H 8
#define ICMP_H 4
自定义数据类型:
#define _u8 unsigned char
#define _u16 unsigned short
#define _u32 unsigned int
后来我发现,好像直接用char数组存储接收到的包就可以。
各种包头:
/* Dest MAC(6), Source MAC(6), Type(2), data(46-1500), CRC(4) */
typedef struct enode{
unsigned char dest_mac[6];
unsigned char src_mac[6];
unsigned short proto;
}ethhd;
/* PPPoE 0x8864; 5byte head, protocol: LCP(0xC021), NCP(0x8021), IP(0x0021) */
/* version(4bit), type(4bit), code(1), session-ID(2), length(2), protocol(2) */
typedef struct ppp_node{
_u8 ver:4,// 标志
type:4;// 地址
_u8 code;// 代码
_u8 id[2];// 会话
_u8 len;// 长度, 此处和所谓ID本人不能确定
_u16 proto;// 协议
_u8 unknown;// 本人怀疑是检验和
}ppp_hd;
/*ipv4 0x0800; 20 byte head, the last 4 byte is options*/
/*ip_hl(4bit), ip_v(4bit), ip_tos(1), ip_len(2), ip_id(2), ip_off(2), ip_ttl(1), ip_p(1), ip_sum(2), ip_src(4), ip_dst(4), options(4) */
typedef struct ipv4_node{
#if defined(LITTLE_ENDIAN)
_u8 ihl:4,// 4位IP头部长度,以4字节为单位
ver:4;// 4bit version number
#elif defined(BIG_ENDIAN)
unsigned char ver:4,
ihl:4;
/* 纯属练习,因为我已经定义。而且动态修改的。
* Purely practice, because I have defined it. And the program will confirm it every time it runs
*/
#else
#error "Sorry, please check head.h and add "#include <types.h>""
#endif
_u8 tos; // 服务类型,各种优先级
_u16 len;// IP部分总长度,包括IP头部和IP的数据部分
_u16 id;// 标识,大的数据包分片后有同一标识,所以能重装
_u16 frag_off;// 片偏移,以8字节为单位,
_u8 ttl;// 生存时间
_u8 proto;// 协议类型
_u16 check;// 头部校验和
_u32 saddr;// 源IP地址
_u32 daddr;// 目的IP地址
_u32 option;// 选项字段
}ip_hd;
/*ipv6 0x86DD; 40 byte head*/
/*source ip start in 8 byte, dest ip start in 24 byte, all is 40 byte */
typedef struct ipv6_node{
#if defined(LITTLE_ENDIAN)
_u32 ver:4,
type:8,
stream:20;
#elif defined(BIG_ENDIAN)
_u32 stream:20,// 流标签, 标志同属一个业务的包
type:8,// 类别,类似ipv4的服务类型
ver:4; // 版本,6
#else
#error "Sorry, please check head.h and add "#include <types.h>""
#endif
_u16 len;// 负载长度, 即不包括ipv6头部的包长度
_u8 head;// ipv6协议内协议的头部,从ipv6头部算起
_u8 ttl;// 跳限
_u8 saddr[16];// 源IP
_u8 daddr[16];// 目的IP
}ip6_hd;
/*arp 0x0806; 24 byte head*/
/*ar_hrd(2), ar_pro(2), ar_hln(1), ar_pln(1), ar_op(2), ar_sha(6), ar_ip(2), ar_dha(6), ar_dip(2) */
typedef struct anode{
_u16 hd;// 硬件类型
_u16 proto;// 协议类型
_u8 hln;// 硬件地址长度
_u8 pln;// 协议地址长度
_u16 op;// 操作码
unsigned char src_mac[ETH_ALEN];// 发送方MAC地址
unsigned char sip[4];// 发送方IP地址
unsigned char dest_mac[ETH_ALEN];// 接收方MAC地址
unsigned char dip[4];// 目的IP地址
}arp_hd;
/* tcp 6; 20 byte head*/
/* source port(2), destination port(2), serial number(4), confirmation number(4), head lenth(4bit),
* retention(6bit), urgentpointer: urg(1bit), acknowledge: ack(1bit), psh(1bit), restart touch: rst(1bit),
* synchronous number: syn(1bit), finally: fin(1bit), windows(2), CRC(2), emergency pointer(2), options(4)
*/
typedef struct tnode{
_u16 sport;// 源端口
_u16 dport;// 目的端口
_u32 seq;// 序列号
_u32 ack_seq;// 确认序列号
#if defined(LITTLE_ENDIAN)
_u16 ret: 4,// 保留
hln: 4,// 头部长度
fin: 1,// 关闭连接标志
syn: 1,// 请求连接标志
rst: 1,// 重置连接标志
psh: 1,// 接收方尽快递交给应用层
ack: 1,// 确认序号标志
urg: 1,// 紧急指针标志
ece: 1,// 拥塞标志位
cwr: 1;// 拥塞标志位
#elif defined(BIG_ENDIAN)
_u16 ret: 4,// 保留
cwr: 1,// 拥塞标志位
ece: 1,// 拥塞标志位
urg: 1,// 紧急指针标志
ack: 1,// 确认序号标志
psh: 1,// 接收方尽快递交数据给应用层
rst: 1,// 重置连接标志
syn: 1,// 请求连接标志
fin: 1;// 关闭连接标志
#else
#error "Sorry, please check head.h and add "#include <types.h>""
#endif
_u16 window;// 滑动窗口大小
_u16 check;// 校验和
_u16 urg_ptr;// 紧急字段标志
}tcphd;
/* UDP 17; 8 byte head*/
/* source port(2), dest port(2), UDP len(2), CRC(2) */
typedef struct unode{
_u16 sport;// 源端口
_u16 dport;// 目的端口
_u16 uln;// UDP包长度 = UDP头部 + 数据
_u16 check;// 校验和
}udphd;
/* ICMP 2; basic 4 byte */
/* type(1), code(1), check sum(2) */
typedef struct inode{
_u8 type;// 消息类型
_u8 code;// 消息类型的子码
_u16 check;// 校验和
union{
struct {// type = 3, 4, 11, 5
_u32 unused;// 多数情况下未使用, 设为全0;type = 5时为目标路由器IP
_u8 buf[IP_MAX_H + 8];// 收到的IP数据包首部及数据前八个字节
}usual;
struct{// type = 12, code = 0
_u8 point;
_u8 other[3];
_u8 buf[IP_MAX_H + 8];
}para;
struct{// type = 0 || 8, code = 0, echo message or echo reply message
_u16 id;// Identifier,识别码
_u16 seq;// Sequence Number, 序列号
_u8 data[IP_MAX_H + 8];
}echo;
struct {// type = 13 || 14, code = 0
_u16 id;
_u16 seq;
_u32 ot;// Originate Timestamp
_u32 rt;// Receive Timestamp
_u32 tt;// Transmit Timestamp
}time;
struct{// type = 10, 15,16, code = 0,
_u16 id;
_u16 seq;
}info;
struct{// type = 9, code = 0
_u8 an;// address number
_u8 aln;// address lenght
_u16 ttl;//
_u8 route[ETH_FRAME_LEN - ETH_H - IP_H];// routing address, refefence, ……
}rout;
}un;
}icmphd;
typedef struct gnode{
_u8 type;// 类型
/* 0x11 Membership Query
* 0x22 Version 3 Membership Report
* 0x12 Version 1 Membership Report
* 0x16 Version 2 Membership Report
* 0x17 Version 2 Leave Group
*/
_u8 mrc;// max responding time
_u16 check;// 校验和, IGMP校验和,16位 校验和是从IGMP类型开始的IGMP报文中16位二进制反码和的16位二进制反码值。
union{
struct{// 0x11
_u32 add;// general query: set to 0; other: IP multicast address
#if defined(LITTLE_ENDIAN)
_u8 resv:4,// Reserved, set to zero on transmission, and ignored on reception.
s:1,// 1阻止路由器定时更新组成员信息
qrv:3;//
#elif defined(BIG_ENDIAN)
_u8 qrv:3,
s:1,
resv:4;
#else
#error "Sorry, please check head.h and add "#include <types.h>""
#endif
_u16 ns;// number of sources
_u32 ga;// Group Address 组地址, 最多可以有336组。
}query;
struct{// 0x22, report, reserved
_u16 resv;// 0, 否则和ns一起组成组播地址, 而下面的ga也是地址
_u16 ns;// number of sources
_u32 ga;// Group Record, 组成员记录,有几种不同方式,本人暂时不想再细分了
}report;
}un;
}igmphd;
其中关于PPPoE、IGMP的,有些地方没弄清楚,但总算可以辨别了。希望了解或者有资料的读者在下面的网址留下它们的结构:http://q-tian.iteye.com
发现RFC文档是个好东西,有个IETF的网站有很多专业规范的资料,不过是英文的。那个IGMP我就是参考了其中一份IGMPv3文档。
记得看到电视剧《网球王子》里某个人总是喜欢说:你还差得远呢!是的,现在离高手还差得远,然而,正因如此,前途不可限量,哈哈!!
源代码,,由于本人写的比较粗糙,故而,还是不上传了。
谢谢你看到这里。坚持的人会有奖品的!
现在我把linux系统定义的相关头文件整理了以下,打包成sniffer.tar.gz,以上的头部定义和其它一些有用的东西都在里面。希望能对你有帮助!
友情提示:不要直接用这些头文件。可以从中截取你要的放到程序里。