一、
根据教材参考代码,编写有个简单网络抓包工具。要求核心代码和运行结果截图1-2张。
- 首先再再再次感谢启龙同学,这次作业或许对于有基础的人来说并不难,但对于我这种基础很差、网络协议都是上学期自己补课的人来说属实有点难度,若不是启龙同学的帮助提供程序并解答我的部分疑惑,我怕是不可能按时完成这次作业。
- 虽然我尽力想要弄明白程序的原理,但是我能力有限,再加上时间也不充裕(其他学科的作业和导师的学习任务也占据了不少时间),所以我只能大概描绘一下我运行这个程序时的流程,如果后续我还有余力的话,我会来更新博客。
程序运行结果
程序代码和分析
首先我先把的代码贴上
constant.h
#include
#include
#include
#include "util.h"
#define INTRODUCTION "Author hanbing nudt.\n\
Simple packet dump"
#define COMMAND_BUFFER_SIZE 50
#define COMMAND_CODE_QUIT 1 /*command quit*/
#define COMMAND_QUIT "quit"
#define COMMAND_CODE_LIST_ALL_DEVICE 2 /*list all valiable device*/
#define COMMAND_LIST_ALL_DEVICE "show-device"
#define COMMAND_CODE_SHOW_OPTIONS 3 /*show options of setting a filter*/
#define COMMAND_SHOW_OPTIONS "show-options"
#define COMMAND_CODE_SET 4
#define COMMAND_SET "set"
#define TOKEN " "
#define COMMAND_CODE_BEGIN 5
#define COMMAND_BEGIN "begin"
- 这个头文件里都是一些宏定义,我就不详细说了。
- 接下来是各个协议的头部定义
#include
#define ETHERNET_HEADER_LENGTH 14
#define IP_HEADER_LENGTH 20
#define IMCP_HEADER_LENGTH 8
/*tls 头部定义*/
struct tls_header
{
};
/*UDP头部格式定义*/
struct udp_header
{
u_int16_t udp_source_port; //源端口号
u_int16_t udp_destination_port; //目的端口号
u_int16_t udp_length; //长度
u_int16_t udp_checksum ; //校验和
};
struct tcp_header
{
u_int16_t tcp_source_port;
u_int16_t tcp_destination_port;
u_int32_t tcp_syn; //SYN number
u_int32_t tcp_ack; //ACK number
#ifdef WORDS_BEGENDIAN
u_int8_t tcp_offset:4,
tcp_reserved:4;
#else
u_int8_t tcp_reserved:4,
tcp_offset:4;
#endif
u_int8_t tcp_flags;
u_int16_t tcp_windows;
u_int16_t tcp_checksum;
u_int16_t tcp_urgent_pointer;
};
/*ICMP头部格式定义*/
struct icmp_header
{
u_int8_t icmp_type;
u_int8_t icmp_code;
u_int16_t icmp_checksum;
u_int16_t icmp_id;
u_int16_t icmp_sequence;
};
/*IP协议头部格式*/
struct ip_header
{
#ifdef WORDS_BEGENDIAN
u_int8_t ip_version:4, //ip协议版本
ip_header_length:4; //ip协议首部长度
#else
u_int8_t ip_header_length:4, //ip协议首部长度
ip_version:4; //ip协议版本
#endif
u_int8_t ip_tos; /*TOS服务质量*/
u_int16_t ip_length; //总长度
u_int16_t ip_id; //标识
u_int16_t ip_off;//偏移
u_int8_t ip_ttl; /*生存时间*/
u_int8_t ip_protocol; //协议类型
u_int16_t ip_checksum; //校验和
struct in_addr ip_source_address; //源ip地址
struct in_addr ip_destination_address; //目的ip地址
};
/*arp protocol format*/
struct arp_header
{
u_int16_t arp_hardware_type; /*硬件地址类型 Ethernet is 1*/
u_int16_t arp_protocol_type; /*网络层协议类型 ipv4 0x0800*/
u_int8_t arp_hardware_length; /*硬件地址长度*/
u_int8_t arp_protocol_length; /*网络层协议地址长度*/
u_int16_t arp_operation_code; /*操作类型 1 request 2 reply*/
u_int8_t arp_source_ethernet_address[6]; /*源以太网地址*/
u_int8_t arp_source_ip_address [4]; /*源ip地址*/
u_int8_t arp_destination_ethernet_address[6]; /*目的以太网地址*/
u_int8_t arp_destination_ip_address [4]; /*目的ip地址*/
};
//util to get ethernet packets
struct ether_header //data structure of ethernet protocol
{
u_int8_t ether_dhost[6]; //Destination address
u_int8_t ether_shost[6]; //Source address
u_int16_t ether_type; //Ethernet type
};
void arp_protocol_packet_callback(u_char *argument,
const struct pcap_pkthdr *packet_header,
const u_char *packet_content);
void ethernet_protocol_packet_callback(u_char *argument, //arguments pass by user
const struct pcap_pkthdr *packet_header,
const u_char *packet_content);
void ip_protocol_packet_callback(u_char *argument, //arguments pass by user
const struct pcap_pkthdr *packet_header,
const u_char *packet_content);
void icmp_protocol_packet_callback(u_char *argument, //arguments pass by user
const struct pcap_pkthdr *packet_header,
const u_char *packet_content);
void udp_protocol_packet_callback(u_char *argument, //arguments pass by user
const struct pcap_pkthdr *packet_header,
const u_char *packet_content);
void tcp_protocol_packet_callback(u_char *argument, //arguments pass by user
const struct pcap_pkthdr *packet_header,
const u_char *packet_content);
#endif
-
然后是callback.c文件。在这个文件中主要是对各个协议的分析
-
Callback.c里的函数
-
void tcp_protocol_packet_callback 输出源端口、目标端口、并根据端口判别应用层协议输出,输出标志位、输出窗口大小、输出校验和、输出紧急指针,总之把头部里能输出的都输出了
-
void udp_protocol_packet_callback 输出源端口、目标端口、并根据端口判别应用层协议输出,输出长度、输出校验和
-
void icmp_protocol_packet_callback 跳过IP协议头部,直接获取IP数据包中icmp协议,如果是回显请求或者回显应答数据包,就输出icmp的类型。然后统一输出标识符、序列号、校验和
-
void arp_protocol_packet_callback 输出硬件类型、协议类型、硬件长度、操作码、请求协议还是相应协议、arp还是rarp、源ip和mac,目标ip和mac
-
void ip_protocol_packet_callback 输出IP版本、头长度、总长度、服务类型、标识、偏移、TTL、校验和、源地址和目标地址、并判定传输层协议,然后扔到相应的callback函数中
-
void ethernet_protocol_packet_callback 输出目的mac地址和源mac地址,然后根据上层协议类型扔到ip或者arp的函数。
#include "callback.h"
static int number = 0;
void tls_protocol_packet_callback(u_char *argument, //arguments pass by user
const struct pcap_pkthdr *packet_header,
const u_char *packet_content)
{
}
void tcp_protocol_packet_callback(u_char *argument, //arguments pass by user
const struct pcap_pkthdr *packet_header,
const u_char *packet_content)
{
struct tcp_header *tcp_protocol;
u_char flags;
int header_length;
u_short source_port;
u_short destination_port;
u_short windows;
u_short urgent_pointer;
u_int sequence;
u_int acknowlegement;
u_int16_t checksum;
tcp_protocol=(struct tcp_protocol*)(packet_content+ETHERNET_HEADER_LENGTH+IP_HEADER_LENGTH);//以太头部长度和ip头部长度
source_port = ntohs(tcp_protocol->tcp_source_port);//回调函数实现ip分析,找出tcp头部中的源端口号,下同
destination_port = ntohs(tcp_protocol->tcp_destination_port);
header_length = tcp_protocol->tcp_offset * 4;
sequence = ntohs(tcp_protocol->tcp_syn);
acknowlegement = ntohs(tcp_protocol->tcp_ack);
windows = ntohs(tcp_protocol->tcp_windows);
urgent_pointer = ntohs(tcp_protocol->tcp_windows);
flags = tcp_protocol->tcp_flags;
checksum = ntohs(tcp_protocol->tcp_checksum);
printf("--------------------TCP Protocol (Transport Layer)--------------------------\n");
printf("Source Port: %d\n",source_port );
printf("Destination Port: %d\n",destination_port );
switch(destination_port) //判断上层协议 通过端口判断应用层协议
{
case 80:printf("HTTP protocol \n");break;
case 21:printf("FTP protocol \n");break;
case 23:printf("Telnet protocol \n");break;
case 25:printf("SMTP protocol \n");break;
case 110:printf("POP3 protocol\n");break;
case 443:printf("HTTPS protocol \n");break;
default:break;
}
printf("Sequence Number: %u\n",sequence );
printf("Acknowlegement Number: %u\n", acknowlegement ); //%u unsigned integer
printf("Header Length: %d\n",header_length );
printf("Reserve: %d\n",tcp_protocol->tcp_reserved );
//提取标志位
if (flags & 0x20)printf("URG");
if (flags & 0x01)printf("FIN");
if (flags & 0x04)printf("RST");
if (flags & 0x08)printf("PSH");
if (flags & 0x10)printf("ACK");
if (flags & 0x02)printf("SYN");
printf("\n");
printf("Window Size: %d\n",windows );
printf("Checksum: %d\n", checksum);
printf("Urgent Pointer: %d\n",urgent_pointer );
switch(destination_port) //判断上层协议
{
case 443:
tls_protocol_packet_callback(argument,packet_header,packet_content);
break;
default:
break;
}
}
void udp_protocol_packet_callback(u_char *argument, //arguments pass by user
const struct pcap_pkthdr *packet_header,
const u_char *packet_content)
{
struct udp_header *udp_protocol; //UDP协议变量
u_short source_port; //源端口号
u_short destination_port; //目的端口号
u_short length; //长度
/*获得ICMP协议数据内容,跳过以太网协议与ip协议部分*/
udp_protocol = (struct udp_header *)(packet_content+ETHERNET_HEADER_LENGTH+IP_HEADER_LENGTH);
source_port = ntohs(udp_protocol->udp_source_port);
destination_port = ntohs(udp_protocol->udp_destination_port);
length = ntohs(udp_protocol->udp_length);
printf("-------------------------UDP Protocol (Transport Layer) ----------------------\n");
printf("Source port: %d\n", source_port);
printf("Destination port: %d\n", destination_port);
switch(destination_port)
{
//NetBios数据报服务
case 138: printf("NETBIOS Datagram Service\n"); break;
case 137: printf("NETBIOS Name Service\n"); break;
case 139: printf("NETBIOS Session Service\n"); break;
case 53:printf("name-domain server \n");break;
default:break;//其他端口号在此没有分析,后续版本会添加
}
printf("Length:%d \n", length );
printf("Checksum: %d\n", ntohs(udp_protocol->udp_checksum)); //获得校验和
}
void icmp_protocol_packet_callback(u_char *argument, //arguments pass by user
const struct pcap_pkthdr *packet_header,
const u_char *packet_content)
{
struct icmp_header *icmp_protocol;
/*获得ICMP协议数据内容,跳过以太网协议与ip协议部分*/
icmp_protocol = (struct icmp_header *) (packet_content+ETHERNET_HEADER_LENGTH+IP_HEADER_LENGTH);
printf("---------------ICMP Protocol (Transport Layer)---------------------");
printf("ICMP Type: %d\n",icmp_protocol->icmp_type );
switch(icmp_protocol->icmp_type) //ICMP数据包类型较多,待扩展
{
case 8://回显请求ICMP数据包
printf("ICMP Echo REquest Protocol \n");
printf("ICMP Identifier: %s\n", icmp_protocol->icmp_id);
printf("ICMP Sequence Number: %s\n", icmp_protocol->icmp_sequence);
break;
case 0://回显应答数据包
printf("ICMP Echo Reply Protocol \n");
printf("ICMP Identifier: %s\n", icmp_protocol->icmp_id);
printf("ICMP Sequence Number: %s\n", icmp_protocol->icmp_sequence);
break;
default:
printf("Header Data %s%s\n", icmp_protocol->icmp_id,icmp_protocol->icmp_sequence);
}
printf("ICMP Checksum:%d\n",ntohs(icmp_protocol->icmp_checksum) );
printf("ICMP Payload: %s", packet_content+
ETHERNET_HEADER_LENGTH+IP_HEADER_LENGTH+IMCP_HEADER_LENGTH);
}
/*arp协议分析回调函数*/
void arp_protocol_packet_callback(u_char *argument,
const struct pcap_pkthdr *packet_header,
const u_char *packet_content)
{
struct arp_header *arp_protocol; //协议头变量
u_short protocol_type; //协议类型
u_short hardware_type; //硬件协议类型
u_short operation_code; //操作类型
u_char *mac_string; //以太网地址
struct in_addr source_ip_address;
struct in_addr destination_ip_address;
u_char hardware_length; //硬件地址长度
u_char protocol_length; //协议地址长度
printf("---------- ARP Protocol (Network Layer) ---------------\n");
/*获得arp协议数据。逐一在这里要跳过以太网数据部分*/
arp_protocol = (struct arp_header *)(packet_content+ETHERNET_HEADER_LENGTH);
/*使用ntohs函数将网络字节序转换为本机字节序*/
hardware_type = ntohs(arp_protocol->arp_hardware_type);
protocol_type = ntohs(arp_protocol->arp_protocol_type);
operation_code = ntohs(arp_protocol->arp_operation_code);
hardware_length = arp_protocol->arp_hardware_length;
protocol_length = arp_protocol->arp_protocol_length;
printf("ARP Hardware Type: %d\n", hardware_type);//输出硬件类型
printf("ARP Protocol Type: %d\n",protocol_type);//输出协议类型
printf("ARP Hardware Length: %d\n", hardware_length);//输出硬件长度
printf("ARP Operation: %d\n", operation_code);//输出操作码
switch(operation_code){//根据操作吗判别清秀协议还是响应协议,是arp还是逆向的rarp
case 1: printf("ARP Request Protocol\n"); break;
case 2: printf("ARP Reply Protocol\n"); break;
case 3: printf("RARP Request Protocol\n"); break;
case 4: printf("RARP Reply Protocol\n"); break;
default: break;
}
printf("Ethernet Source Address is : \n");
mac_string = arp_protocol->arp_source_ethernet_address;
printf("%02x:%02x:%02x:%02x:%02x:%02x:\n",*(mac_string),
*(mac_string+1),*(mac_string+2),*(mac_string+3),*(mac_string+4),
*(mac_string+5) );
memcpy((void *) &source_ip_address, (void *) &arp_protocol->
arp_source_ip_address, sizeof(struct in_addr));
printf("Source IP Address: %s\n", inet_ntoa(source_ip_address));
printf("Ethernet destination_ip_address Address is : \n");
mac_string = arp_protocol->arp_destination_ethernet_address;
printf("%02x:%02x:%02x:%02x:%02x:%02x\n",*(mac_string),
*(mac_string+1),*(mac_string+2),*(mac_string+3),*(mac_string+4),
*(mac_string+5) );
memcpy((void *) &destination_ip_address, (void *) &arp_protocol->
arp_destination_ip_address, sizeof(struct in_addr));
printf("Destination IP Address: %s\n", inet_ntoa(destination_ip_address));
}
/*回调函数实现ip协议包分析*/
void ip_protocol_packet_callback(u_char *argument, //arguments pass by user
const struct pcap_pkthdr *packet_header,
const u_char *packet_content)
{
struct ip_header *ip_protocol;
u_int header_length;
u_int offset;
u_char tos;
u_int16_t checksum;
/*去掉以太网头部,获得ip协议数据内容*/
ip_protocol = (struct ip_header *)(packet_content + ETHERNET_HEADER_LENGTH);
checksum = ntohs(ip_protocol->ip_checksum);
header_length = ip_protocol->ip_header_length*4;
tos = ip_protocol->ip_tos;
offset = ntohs(ip_protocol->ip_off);
printf("------------------IP Protocol (Network Layer)----------------------\n");
printf("IP Version: %d\n",ip_protocol->ip_version);
printf("Header_length: %d\n",header_length);
printf("Tos:%d\n", tos);
printf("Total length: %d\n", ntohs(ip_protocol->ip_length));
printf("Identification: %d\n",ntohs(ip_protocol->ip_id) );
printf("offset: %d\n",(offset & 0x1fff)*8 );
printf("TTL: %d\n",ip_protocol->ip_ttl );
printf("Protocol: %d\n",ip_protocol->ip_protocol );
switch(ip_protocol->ip_protocol)
{
case 6: printf("The Transport Layer Protocol is TCP\n");break;
case 17: printf("The Transport layer Protocol is UDP\n");break;
case 1: printf("The Transport layer Protocol is ICMP\n");break;
default:
break;
}
printf("Header checksum: %d\n", checksum);
printf("Source address: %s\n",inet_ntoa(ip_protocol->ip_source_address));
printf("Destination address: %s\n", inet_ntoa(ip_protocol->ip_destination_address));
switch(ip_protocol->ip_protocol)
{
case 6: tcp_protocol_packet_callback(argument,packet_header,packet_content);break;
case 17: udp_protocol_packet_callback(argument,packet_header,packet_content);break;
case 1: icmp_protocol_packet_callback(argument,packet_header,packet_content);break;
default:
break;
}
}
/*回调函数实现以太网协议分析*/
void ethernet_protocol_packet_callback(u_char *argument, //arguments pass by user
const struct pcap_pkthdr *packet_header,
const u_char *packet_content){
pcap_dump(arguement, packet_header, packet_content);
number++;
printf("\n");
printf("\n");
printf("The num %d packets\n", number);
u_short ethernet_type; //以太网类型
struct ether_header *ethernet_protocol; //以太网协议类型
u_char *mac_string; //以太网地址
static int packet_number = 1;
printf("--------------------Ethernet Protocol (Link Layer)-------------------\n");
ethernet_protocol = (struct ethernet_header *)packet_content;
/*获得以太网协议数据*/
printf("Ethernet type is : \n");
ethernet_type = ntohs(ethernet_protocol->ether_type);//获得以太网类型
printf("%04x\n",ethernet_type );
switch(ethernet_type)
{
case 0x0800: printf("The network layer is IP protocol\n");break;
case 0x0806: printf("The network layer is ARP protocol\n");break;
case 0x0835: printf("The network layer is RARP protocol\n");break;
}
/*获得源以太网地址*/
printf("Mac Source Address is : \n");
mac_string = ethernet_protocol->ether_shost;
printf("%02x:%02x:%02x:%02x:%02x:%02x\n",*(mac_string),
*(mac_string+1),*(mac_string+2),*(mac_string+3),*(mac_string+4),
*(mac_string+5) );
/*获得目的以太网地址*/
printf("Mac Destination Address is : \n");
mac_string = ethernet_protocol->ether_dhost;
printf("%02x:%02x:%02x:%02x:%02x:%02x\n",*(mac_string),
*(mac_string+1),*(mac_string+2),*(mac_string+3),*(mac_string+4),
*(mac_string+5) );
/*调用上层协议分析回调函数*/
switch(ethernet_type)
{
case 0x0800: ip_protocol_packet_callback(argument,packet_header,packet_content);
break;
case 0x0806: arp_protocol_packet_callback(argument,packet_header,packet_content);
break;
case 0x0835: break;
default: break;
}
printf("-------------------------------------------------------------------------\n");
}
-
可以看出来上面的函数层层递进得来分析协议,先是对以太网帧进行分析,然后根据分析得出来的上层协议,来转到IP或者ARP的分析函数。
-
然后在IP的分析函数中,也是通过分析数据,来转到TCP、UDP或者ICMP的函数中。
-
分析完上面的几个文件之后,我是从main函数开始,将我的抓包过程的所经历的程序分析了一遍。
-
首先是main.c文件
#include "constant.h"
static char buffer[COMMAND_BUFFER_SIZE];
static int command_code;
static filter_options_t options;
void init_interpreter(){
puts(INTRODUCTION);
}
void PrintUsage(){
printf("%s\n", USAGE);
}
void show_options(){
printf("过滤规则: %s\n", options.filter);
printf("网络设备: %s\n",options.device);
}
int ParseCommandLine(char *command){
if (strcmp(command,COMMAND_QUIT) == 0)
{
command_code = COMMAND_CODE_QUIT;
return 0;
}
else if (strcmp(command,COMMAND_LIST_ALL_DEVICE) == 0)
{
command_code = COMMAND_CODE_LIST_ALL_DEVICE;
return 0;
}
else if (strcmp(command,COMMAND_SHOW_OPTIONS) == 0)
{
command_code = COMMAND_CODE_SHOW_OPTIONS;
return 0;
}
else if(strcmp(command,COMMAND_BEGIN) == 0){
command_code = COMMAND_CODE_BEGIN;
return 0;
}
else{
char *tmp = NULL;
tmp = strtok(command,TOKEN);
if (strcmp(tmp,COMMAND_SET) == 0)
{
if(pares_option_setting()){
command_code = COMMAND_CODE_SET;
return 0;
}
}
}
command_code = 0;
return 1;
}
int pares_option_setting(){
char *tmp;
char *option;
tmp = strtok(NULL,TOKEN);
if (!tmp)
{
return 0; //false
}
option = strtok(NULL,TOKEN);
if (!option)
{
return 0; //false
}
if (strtok(NULL,TOKEN))
{
return 0;
}
if (!strcmp(tmp,"device"))
{
strcpy(options.device,option);
return 1;
}
else if(!strcmp(tmp,"filter"))
{
strcpy(options.filter,option);
return 1;
}
else if(!strcmp(tmp,"path"))
{
strcpy(options.path,option);
return 1;
}
else
{
return 0;//false
}
}
int CommandDispacther(){
switch(command_code){
case COMMAND_CODE_QUIT:
return 0; //return status code 0 when quit
case COMMAND_CODE_LIST_ALL_DEVICE:
findalldevs();
return 1;
case COMMAND_CODE_SHOW_OPTIONS:
show_options();
return 1;
case COMMAND_CODE_SET:
return 1;
case COMMAND_CODE_BEGIN:
capture_packets(&options);
return 1;
default:
return 0; //defalt retrun true
}
}
int main(int argc, char const *argv[])
{
int status = 1;
init_interpreter();
do{
printf(">>");
gets(buffer);
/*Parse args options*/
if (ParseCommandLine(buffer)){
PrintUsage();
}else{
status = CommandDispacther();
}
} while (status);
return 1;
}
-
这里只看main函数的话是非常的简洁,只有这几行,所以我的运行过程也很简单(如果难的话我应该就看不懂了)
-
main
函数里首先定义了一个作用的变量status
,用于do while
循环。然后void init_interpreter()
就是输出了宏定义的一句话(这个函数删了也没什么影响吧,只是输出一句话了)。然后开始do while
循环。 -
在我的程序里,我第一个输入的
buffer
是set device eth0
这个eth0就是我的网卡。接下看ParseCommandLine(buffer)
。这个函数也在main.c
里面,可以在上面的代码里找到。我输入的很显然不是这些任何一个宏定义,然后转到else
。接着在else里转到下一个pares_option_setting
函数,在这里进行了strcpy(options.device,option)
,将网卡保存了下来。之后可以看到该函数返回了1
,然后继续向上推,上一个函数返回0
,并且将command_code
设置为一个宏定义。接下来回到main
函数,因为if
返回0
,执行else
,在CommandDispacther
里又可以得到返回1.也就是继续进行do while循环
。 -
其实上面的一大串,不过是储存了我设置的网卡,然后继续循环。所以接下来我输入的
set path
也就不再罗里吧嗦的说了,可以顺着看。 -
第三次循环我输入begin。顺着运行可以看到,最后执行了
capture_packets(&options)
这个函数再另一个文件里:
int findalldevs(){
pcap_if_t *alldevs;//网卡链表里的一个元素
pcap_if_t *d;
char *s;
bpf_u_int32 net,mask;
int exit_status = 0;
char errbuf[PCAP_ERRBUF_SIZE+1];
if (pcap_findalldevs(&alldevs, errbuf) == -1)
{
fprintf(stderr,"Error in pcap_findalldevs: %s\n",errbuf);
return 1;
}
for(d=alldevs;d;d=d->next)
{
if (!ifprint(d)){
return 1;
}
}
if ( (s = pcap_lookupdev(errbuf)) == NULL)
{
fprintf(stderr,"Error in pcap_lookupdev: %s\n",errbuf);
exit_status = 2;
}
else
{
printf("Preferred device name: %s\n",s);
}
if (pcap_lookupnet(s, &net, &mask, errbuf) < 0)
{
fprintf(stderr,"Error in pcap_lookupnet: %s\n",errbuf);
exit_status = 2;
}
else
{
printf("Preferred device is on network: %s/%s\n",iptos(net), iptos(mask));
}
return exit_status;
}
void capture_packets(struct filter_options *options){
char error_content[PCAP_ERRBUF_SIZE];
pcap_t *pcap_handle;
bpf_u_int32 net_mask; //netmask
bpf_u_int32 net_ip; //net ip
char *net_interface;
struct bpf_program bpf_filter; //bpf过滤规则
char *bpf_filter_string = options->filter; //bpf过滤规则
//net_interface = pcap_lookupdev(error_content); /*获取网络接口*/
net_interface = options->device;
printf("net_interface :%s\n", net_interface);
/*获取网络地址和掩码地址*/
pcap_lookupnet(net_interface,//该函数用于获得网卡所在网络的网络地址和子网掩码。
&net_ip,
&net_mask,
error_content);
/*打开网络接口*/
pcap_handle = pcap_open_live(net_interface,// 该函数用于打开指定设备的网络捕获,获得数据包捕获描述字
BUFSIZ,
1, /*混杂模式*/
0, /*等待实践*/
error_content);
if (!pcap_handle)
{
printf("打开网络接口失败,请检查输入的网络接口是否存在,或者是否具有权限打开此网络接口。\n");
return;
}
/*编译并设置bpf过滤规则*/
if (pcap_compile(pcap_handle, &bpf_filter,bpf_filter_string,0,net_mask))
{
printf("请检查你的输入规则是否有误。\n");
return;
}
pcap_setfilter(pcap_handle,&bpf_filter);//函数用于指定一个过滤程序,出错时返回-1
if (pcap_datalink(pcap_handle) != DLT_EN10MB)
{
return;
}
pcap_dumper_t* out_pcap = NULL;
out_pcap = pcap_dump_open(pcap_handle,options->path);//打开用于保存数据包的文件,用于写入
pcap_loop(pcap_handle,//用来捕获数据包时用的。捕获了符合要求的数据包就交给回调函数。
,ethernet_protocol_packet_callback //开始一层层揭开
,(u_char *)out_pcap); //pass arguments to callback
pcap_close(pcap_handle);//关闭指针相应的文件,释放资源
pcap_dump_close(out_pcap);//关闭被打开的文件
}
-
可以看到这里开始有了很多的pcap的函数和数据类型。我再网上找了一些大致的简介。
-
pcap_t
一种结构体。详细参考来自这里 -
关于函数的简介,我在尝试读程序的时候在注释里写了一些,程序本身也带有一些注释,并且网上对一些函数的详细功能描述也是不清不楚,甚至有的还有歧义,我只是结合这个程序把我认为正确的解释写到了注释里,但是我没有经过实践去验证,就不详细写了。
-
然后注意
ethernet_protocol_packet_callback
,开始使用回调函数。在前面我也提到,在以太网帧解析完毕之后会一层层传递,也就是这一句函数就把这个数据解释完毕了。 -
然后再看回mian函数,这个时候就应该输入
COMMAND_QUIT
的宏定义准备退出了。但是我每次都是CTRL+C
直接结束,所以没有截图。。。 -
可以看到我对这个程序并没有很全面的掌握。比如我在运行时没用到的程序。比如lipacp函数的详细原理(这个我尽力看了,但是我真的在短时间内看不很懂,好多基础知识都不了解,考虑自己的似懂非懂的状态不好意思献丑,所以我没有解释libpacp的函数)。之后有时间我会尽力补充。
二、
找一个网站或者搭建一个本地网站,登录网站,并嗅探,分析出账号和密码,结果截图1-2张。
-
由于我不会搭建网站,所以就想登录别的网站然后抓包。但是尴尬的是所有的网站都在加密,抓下来我也只能知道密文。这个让人很是头疼。
-
在同学的帮助下,我了解了POP3的服务是明文。我就下载了一个foxmail,然后在用foxmail登录的过程取消了ssl加密
-
结果
- 当然这里的不是我的密码,是pop3的授权码,我已经禁止pop3了所以没有打马赛克。