免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1852 | 回复: 6
打印 上一主题 下一主题

小弟最近在读linsniffer的源代码,有个问题向大家请教: [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2004-05-05 13:51 |只看该作者 |倒序浏览
以下是对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“,小弟一直不理解它的作用,请大家帮我解释一下。

论坛徽章:
0
2 [报告]
发表于 2004-05-05 16:59 |只看该作者

小弟最近在读linsniffer的源代码,有个问题向大家请教:

((unsigned long)&ep.ip)就是取ep结构的ip成员的地址并转换成无符号长整数。(((unsigned long)&ep.ip)-2)就是把指针向前移动2个字节,具体是做什么,我也不清楚。

论坛徽章:
0
3 [报告]
发表于 2004-05-05 18:21 |只看该作者

小弟最近在读linsniffer的源代码,有个问题向大家请教:

[quote]原帖由 "kj501"]((unsigned long)&ep.ip)就是取ep结构的ip成员的地址并转换成无符号长整数。(((unsigned long)&ep.ip)-2)就是把指针向前移动2个字节,具体是做什么,我也不清楚。[/quote 发表:


(((unsigned long)&ep.ip)-2)是移动2*sizeof(unsigned long)字节吧

论坛徽章:
0
4 [报告]
发表于 2004-05-06 09:37 |只看该作者

小弟最近在读linsniffer的源代码,有个问题向大家请教:

呵呵,不好意思,还是楼上兄弟细心。多谢指正! 汗~~!

论坛徽章:
0
5 [报告]
发表于 2004-05-06 10:26 |只看该作者

小弟最近在读linsniffer的源代码,有个问题向大家请教:

谢谢2位的解答,那就是移动了8个字节。

那在这个程序里有什么作用呢?以太网的包头是14字节,ip和tcp的固定包头都是20字节,怎么看也用不到8个字节啊

论坛徽章:
0
6 [报告]
发表于 2004-05-06 15:08 |只看该作者

小弟最近在读linsniffer的源代码,有个问题向大家请教:

ethhdr 结构是14个字节,但是
被分配了16个字节(按4字节对齐了)

(((unsigned long)&ep.ip)-2)是两个字节。

论坛徽章:
0
7 [报告]
发表于 2004-05-07 09:26 |只看该作者

小弟最近在读linsniffer的源代码,有个问题向大家请教:

原帖由 "yy_yangy" 发表:

(((unsigned long)&ep.ip)-2)是两个字节。

我想了一下,应该是这样来理解,(unsigned long)是把地址强制转换成无符号长整型。但这个地址所指向的内容没有改变。所以(((unsigned long)&ep.ip)-2)是移动2个字节。如果是强制转换成(unsigned long *),这才是改变了指针所指向的内容,(((unsigned long *)&ep.ip)-2)才是移动2*(unsigned long)个字节。
btw:看来自己对C还是得好好学习一下。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP