CSDN首页 空间 新闻 论坛 Blog 下载 读书 网摘 搜索 .NET Java 视频 接项目 求职 在线学习 买书 程序员 通知
花落谁家,你作主! 盛大widget设计大赛英雄榜
CSDN社区
搜索 收藏 打印 关闭
CSDN社区 >  C/C++ >  C++ 语言

求高手帮忙,谢谢

楼主bubugo()2005-05-04 18:14:19 在 C/C++ / C++ 语言 提问

这个抓包解包的程序能运行,可是有一个问题就是源IP地址和目的IP地址老是一样的。我想了很久也不知道原因,求教高手  
  #include   <winsock2.h>  
  #include   <ws2tcpip.h>  
  #define   SIO_RCVALL   _WSAIOW(IOC_VENDOR,1)  
  #include   <iostream.h>  
  #include   "stdio.h"  
  #include   <string>  
  //#include   "iostream.h"  
  #include   <list>  
  #include   <vector>  
  using   namespace   std;  
   
   
  #   define   null   0  
  #   define   len   sizeof(struct   node)  
   
  #pragma   comment(lib,"ws2_32")  
   
   
  //#define   TCP   6  
  //#define   UDP   17  
  //#define   ICMP   1  
   
  #define   PROTO_TCP   6  
  #define   PROTO_UDP   17  
  #define   PROTO_ICMP   1  
   
  typedef   struct   ip_header  
  {//   IPv4   包头    
  unsigned   char ver_ihl; //   版本   (4   bits)   +   包头长度(4   bits)  
  unsigned   char tos; //   服务类型    
  unsigned   short     total_len; //   数据包的总长度    
  unsigned   short     id;                           //   ID号  
  unsigned   short     flag_offset; //   标志   (3   bits)   +   分片偏移   (13   bits)  
  unsigned   char ttl; //   生存时间  
  unsigned   char proto; //   协议  
  unsigned   short     checksum; //校验  
  unsigned   int saddr;                         //   源地址  
  unsigned   int daddr;                         //   目的地址  
  unsigned   int         opt;                                         //IP选项和填充  
  }IP_HEADER;  
   
   
  typedef   struct   tcp_header  
  {  
  unsigned   short   sport;  
  unsigned   short   dport;  
  unsigned   long   seq;                               //32位的序列号  
  unsigned   long   ack;                               //32位的确认号  
  unsigned   char   head_len;                     //4位长度和4位保留  
  unsigned   char   flag;                             //标志位(高6位为码元标志位,低2位保留)  
  unsigned   short   win;                             //窗口  
  unsigned   short   checksum;                   //校验和  
  unsigned   short   urg;                             //紧急指针  
  }TCP_HEADER;  
   
  typedef   struct   udp_header  
  {//UDP   头  
  unsigned   short   sport; //   源端口  
  unsigned   short   dport; //   目击端口  
  unsigned   short   length;         //   包长度  
  unsigned   short   checksum;         //   校验  
  }UDP_HEADER;  
   
  typedef   struct   icmp_header  
  {  
          char   type;                       //类型字节(1字节)  
          char   code;                       //代码字节(1字节)  
          unsigned   short   checksum;       //校验码(2字节)  
  }ICMP_HEADER;  
   
  class   RawSocket      
  {  
  public:  
  RawSocket();  
  virtual   ~RawSocket();  
  public:  
  SOCKET   s;  
  char*GetIP();  
  void   NetInit();  
  char*GetRawPacket();  
   
  };  
   
   
   
   
   
  RawSocket::RawSocket()  
  {  
   
  }  
   
  RawSocket::~RawSocket()  
  {  
   
  }  
  char*RawSocket::GetIP()                                                                                           //这个的IP应该是主机的IP?  
  {      
  char*hostname=new   char[256];  
  memset(hostname,0,256);  
  gethostname(hostname,256);  
  struct   hostent   *phost=gethostbyname(hostname);  
  //printf("phost:%d\n",phost);  
  if(phost==NULL)  
  {  
  cout<<"pHost   为空"<<"gethostbyname()错误"<<endl;  
  return   NULL;  
  }  
          in_addr*pAddr=(in_addr*)&phost->h_addr_list[0];  
  //printf("pAddr:%d\n",pAddr);  
          return   inet_ntoa(*pAddr);  
  }  
  void   RawSocket::NetInit()  
  {  
  WSADATA   wsa;  
  if(WSAStartup(MAKEWORD(2,2),&wsa)!=0)  
  {  
  cout<<"WSAStartup   Error:"<<GetLastError()<<endl;  
  return;  
  }  
  s=socket(AF_INET,SOCK_RAW,IPPROTO_IP);  
  if(s==INVALID_SOCKET)  
  {  
  cout<<"Create   socket   error:"<<GetLastError()<<endl;  
  return;  
  }  
   
   
          sockaddr_in   addr;  
  addr.sin_family=AF_INET;  
  addr.sin_addr.s_addr=inet_addr("61.149.185.201");  
  addr.sin_port=ntohs(7000);  
  printf("%d,%d\n",addr.sin_family,addr.sin_port);  
   
  if(bind(s,(sockaddr*)&addr,sizeof(addr))==SOCKET_ERROR)  
  {  
  cout<<"Bind   socket   error:"<<GetLastError()<<endl;  
  return;  
  }  
  DWORD   BytesRet;  
  //if(WSAIoctl(s,SIO_RCVALL,&InBuf,sizeof(InBuf),&OutBuf,sizeof(OutBuf),&BytesRet,NULL,NULL)==SOCKET_ERROR)  
  if(ioctlsocket(s,SIO_RCVALL,&BytesRet)==SOCKET_ERROR)  
  {  
  cout<<"WSAIoctl   error"<<GetLastError()<<endl;  
          return;  
  }  
   
   
  }  
  char*   RawSocket::GetRawPacket()  
  {       int   BUF_SIZE=65535;  
          char   *ret=new   char[BUF_SIZE];  
  memset(ret,0,BUF_SIZE);  
          //printf("recv:%d\n",recv(s,ret,BUF_SIZE,0));  
  if(recv(s,ret,BUF_SIZE,0)==SOCKET_ERROR)  
  {  
  cout<<"another"<<endl;  
  cout<<"Recv   error:"<<GetLastError()<<endl;  
  }  
  //printf("ret:%d\n",ret);  
  return   ret;  
  }  
   
   
   
   
  class   PacketDecode      
  {  
  public:  
  PacketDecode();  
  virtual   ~PacketDecode();  
  public:  
  IP_HEADER   *ih;  
  TCP_HEADER   *th;  
  UDP_HEADER   *uh;  
   
  char   *data;  
   
  void   DecodeInit(char*buf);  
  int   GetProtocol();  
  int   GetTotalLength();  
  char*GetRemoteIP();  
  char*GetLocateIP();  
  int   GetSPort();  
  int   GetDPort();  
  int   GetIPHeadLen();  
  int   GetTCPHeadLen();  
  int   GetUDPHeadLen();  
  int   GetICMPHeadLen();  
   
  char   *GetData();  
  };  
   
   
   
   
  PacketDecode::PacketDecode()  
  {  
        data=new   char[65536];  
  }  
  PacketDecode::~PacketDecode()  
  {  
   
  }  
  void   PacketDecode::DecodeInit(char*buf)  
  {  
  data=buf;  
  //printf("buf:%d\n",buf);  
  ih=(IP_HEADER*)buf;  
  printf("ih:%d,\n",ih);  
  th=(TCP_HEADER*)(buf+GetIPHeadLen());  
  uh=(UDP_HEADER*)(buf+GetIPHeadLen());  
  }  
  int   PacketDecode::GetIPHeadLen()  
  {  
  return   ((ih->ver_ihl)&15)*4;//0x0f=00001111也就是取低4位,且IP包头是以4字节为单位的  
  }  
  int   PacketDecode::GetProtocol()  
  {  
  return   ih->proto;  
   
  }  
   
  int   PacketDecode::GetTotalLength()  
  {  
  return   ntohs(ih->total_len);  
  }  
  char   *PacketDecode::GetLocateIP()                                                                                 //源IP地址  
  {  
  //inet_ntoa(*(in_addr*)&(ih->saddr));  
  //printf("\nsaddr:%d\n",ih->saddr);  
  return   inet_ntoa(*(in_addr*)&(ih->saddr));  
  }  
   
  char   *PacketDecode::GetRemoteIP()                                                                                 //目的地址(本机)  
  {        
  //printf("\ndaddr:%d\n",ih->daddr);  
  return   inet_ntoa(*(in_addr*)&(ih->daddr));  
  }  
   
  int   PacketDecode::GetSPort()  
  {  
  switch(GetProtocol())  
  {  
  case   17:  
  return   ntohs(uh->sport);  
  break;  
  case   6:  
  return   ntohs(th->sport);  
  break;  
  default:  
  return   0;  
   
  }  
  return   0;  
  }  
  int   PacketDecode::GetDPort()  
  {  
  switch(GetProtocol())  
  {  
  case   17:  
  return   ntohs(uh->dport);  
  break;  
  case   6:  
  return   ntohs(th->dport);  
  break;  
  default:  
  return   0;  
  }  
  return   0;  
  }  
  int   PacketDecode::GetTCPHeadLen()  
  {  
  return   20;  
  }  
  int   PacketDecode::GetUDPHeadLen()  
  {  
  return   20;  
  }  
  int   PacketDecode::GetICMPHeadLen()  
  {  
  return   20;  
  }  
  char*PacketDecode::GetData()  
  {  
  switch(GetProtocol())  
  {  
  case   PROTO_TCP:  
  return   data+GetIPHeadLen()+GetTCPHeadLen();  
  case   PROTO_UDP:  
  return   data+GetIPHeadLen()+GetUDPHeadLen();  
  case   PROTO_ICMP:  
  return   data+GetIPHeadLen();  
  }  
   
  }  
   
   
   
   
  struct   node  
  {  
  char   *a1;  
  char   *a2;  
  int   a3;  
  int   a4;  
  int   a5;  
  int   a6;  
  int   a7;  
  int   a8;  
  int   a9;  
  int   a10;  
  char   *a11;  
   
  };  
  void   main()  
  {        
          RawSocket   s;  
        PacketDecode   p;  
   
  struct   node   n;  
   
  while(true)  
  {        
  s.NetInit();  
   
  s.GetIP();                                                                       //主机IP  
  printf("GetIP:%d\n",s.GetIP());  
   
  s.GetRawPacket();  
  printf("GRP:%ld\n",s.GetRawPacket());  
           
  p.DecodeInit(s.GetRawPacket());  
   
  n.a6=p.GetProtocol();  
                  printf("PROTOCOL:%ld\n",n.a6);  
                   
   
  n.a2=p.GetLocateIP();  
                  printf("LocateIP:%ld\n",p.GetLocateIP());  
   
   
  n.a1=p.GetRemoteIP();  
  printf("RemoteIP:%ld\n",n.a1);  
   
  n.a3=p.GetDPort();  
                  printf("Dport:%ld\n",n.a3);  
   
  n.a4=p.GetICMPHeadLen();  
                  printf("ICMPHEADLEN:%ld\n",n.a4);  
   
    n.a5=p.GetIPHeadLen();  
                  printf("IPHEADLEN:%ld\n",n.a5);  
     
  n.a7=p.GetSPort();  
                  printf("SPROT:%ld\n",n.a7);  
     
  n.a8=p.GetTCPHeadLen();  
                  printf("TCPHEADLEN:%ld\n",n.a8);  
   
  n.a9=p.GetTotalLength();  
                  printf("TLENGTH:%ld\n",n.a9);  
   
  n.a10=p.GetUDPHeadLen();  
                  printf("UDPHEADLEN:%ld\n",n.a10);  
   
  n.a11=p.GetData();  
                  printf("DATA:%ld\n\n\n",n.a11);  
  }  
   
  }  
  多谢解答,谢谢 问题点数:20、回复次数:16Top

1 楼zhousqy(标准C匪徒)(甩拉,甩拉)回复于 2005-05-04 21:06:38 得分 0

瓦,这么长。Top

2 楼llf_hust()回复于 2005-05-04 21:07:41 得分 0

帮你UPTop

3 楼foochow(无聊,灌水......)回复于 2005-05-04 21:36:11 得分 0

UPTop

4 楼yuhjnm_20001(力)回复于 2005-05-04 22:52:37 得分 0

dingTop

5 楼ericqxg007(还有很多东西要学(卡卡一米阳光))回复于 2005-05-04 23:05:22 得分 0

~   ~  
      !Top

6 楼xuzheng318(忧郁王子)回复于 2005-05-05 00:38:06 得分 5

IP   数据报的格式    
        TCP/IP协议使用IP数据报包含一个数据报报头和一个数据区。    
        IP数据报头包含有源、目的信息,做寻径用。并且指明承载负载的协议类型。    
  数据报所携带的数据量不固定!下面给出IP数据报的详细格式:    
    0   1   2   3   4   5   6   7     0   1   2   3   4   5   6   7   0   1   2   3   4   5   6   7   0   1   2   3   4   5   6   7    
  -----------------------------------------------------------------|    
        版本   |报头长度|       服务类型         |                   总长度                                 |    
  -----------------------------------------------------------------|    
          标识符               |             标志           |                 分片偏移量                           |    
  -----------------------------------------------------------------|    
          存活时间           |             协议           |                 报头校验和                           |    
  -----------------------------------------------------------------|    
                                                            源地址                                                             |    
  -----------------------------------------------------------------|    
                                                          目的地址                                                           |    
  -----------------------------------------------------------------|    
                          IP选项                               |                     填充                                   |    
  -----------------------------------------------------------------|    
                                                      数据区。。。                                                       |    
  -----------------------------------------------------------------|    
   
              IP数据报的C语言结构:(不包含可选项和填充域)    
  /*The   IP   header   for   VC++   */    
  typedef   struct   tagipheader    
  {    
  unsigned   char   h_len:4;    
  unsigned   char   version:4;    
  unsigned   char   tos;    
  unsigned   short   total_len;    
   
  unsigned   short   ident;    
  unsigned   char   ttl;    
  unsigned   char   proto;    
  unsigned   short   checksum;    
   
  unsigned   int   sourceIP;    
  unsigned   int   destIP;    
  }IPHEADER;    
  2.1   版本协议号    
          IP数据报的第一个域是4bit长的版本域(version)。版本号规定了数据报的格式,    
  不同的IP协议版本其数据报格式有所不同。当前IP协议的版本号为4,称IPv4;下一    
  个将要发展的IP协议,版本号为6,即IPv6。    
  2.2   数据报的长度、填充域和总长度    
          报头长度域(h_len)也是4bit长.它指出报头的长度,如果报头的长度不是32bit的整数    
  倍,则由填充域添0补齐.    
          16bit长的数据报的总长域(total_len),它以字节为单位标定整个IP数据报的长度。    
  由于总长域占16bit,所以数据报最长可达2的16次方减1个字节。    
  2.3   服务类型和优先权    
          8bit长的服务类型域(tos)规定本数据报的处理方式,并分为5个子域,如图:    
          0       1       2       3       4       5       6       7    
  ----------------------------------|    
                              |       传输类型                 |    
              优先权     |-------------------|    
                              |   D   |   T   |   R   |   C   |       |    
  ----------------------------------|    
          3bit的优先级(precedence)子域指明本数据的优先级,允许发送方表示本数据报的重要    
  程度.其取值从0到7,0表示普通优先级,即网络控制优先级.大多数主机和路由器软件对此    
  不予理睬.    
          D、T、R、C位表示本数据报所期望的传输类型。取1时,D代表时延(Delay),   T代表    
  高吞吐量(Throughput),R代表高可靠性(Reliability),C代表低开销。应注意每种网络    
  技术的D、T、R性能之间往往是此强彼弱的。应只指定其中一个!    
  2.4   标识符、标志和分片偏移量    
          网络数据最终都是通过物理网络帧传输,IP数据报也是!整个数据报被封装在一个物理    
  帧中传输时的效率最高。不同物理网络技术所采用的最大帧长是相异的。这个帧长称作为    
  最大传输单元(Maximum   Transfer   Unit,MTU).    
          当数据报分组从一个MTU较大的网络经路由器中继到一个MTU较小的网络上时,由于分组    
  过长,路由器就会拒绝中继或将数据报分片后再传送。分片通常在路由器中完成,而重组由    
  主机的IP协议完成。IP报头中的标识符(ident)、标志和分片偏移量(frag_and_flags)三个    
  域用作分片和重组控制.    
          标识符标识数据报发送的先后顺序,每产生一个新的数据报标识符增1,目的机用来重组分片    
  数据报.同一IP数据报分片后标识符域不变.    
          分片偏移量指完整的数据报内该分片的偏移量.    
          标志域有3个bit位组成,第一位保留为0,如图:    
        0           1           2    
        0         DF           MF    
          DF位表示分组禁止被分片.MF位表示分组片未完.MF位清0,此分片是IP数据报分组的最后一片.    
  2.5   存活时间    
          存活时间(ttl)设置了该数据报在因特网中允许存在的最大生存时间,以秒为单位.每产生一个数据报时,就为它设置了一个最大的生存时间.当数据报通过的主机和路由器对该数据报进行处理时,又减去消耗的时间.一旦时间小于0,便将该数据报从因特网中删除,并向信源机发回错信息.    
          ttl保证了即使路由表不可靠而选择了一个循环路由,数据报都不会在因特网中无休止地流动.    
  2.6   协议序列号    
          协议域表示IP数据报中数据的协议类型,如TCP、UDP、ICMP等。下图列出了IANA已分配的常见协议序列号    
      十进制编号                     关键字                     协议名称    
                0                                                     保留    
                1                             ICMP                 因特网控制报文协议    
                2                             IGMP                 因特网组管理协议    
                3                             GGP                   网关-网关协议    
                4                             IP                     IP里的IP    
                5                             ST                     数据流    
                6                             TCP                   传输控制协议    
                8                             EGP                   外部网关协议    
                17                           UDP                   用户数据报协议    
                29                       ISO-TP4               ISO传输协议类4    
          41~60                                                   未分配    
              70                           VISA                   VISA协议    
              80                         ISO-IP                 ISO网间协议(CLNP)    
              88                           IGRP                   内部网关协议    
              89                         OSPF                     开放式最短路径优先协议    
        99~254                                                   未分配    
            255                                                     保留    
  2.7   源地址和目的地址    
            源IP地址(SourceIP)和目的IP地址(DestIP)域包含数据报的发送方和接受方的IP地址。Top

7 楼foxwing(穿过你的骨髓我的手)回复于 2005-05-05 01:09:07 得分 0

当套接字类型是SOCK_RAW时:  
   
  你调用了bind函数,也就是说61.149.185.201这个地址是本地的,那么你测试程序时在另一台机器上就必须指明以61.149.185.201作为目的地址。例如在另一台机器上用ping命令时,就必须这样:  
  ping   61.149.185.201  
  这样你的机器收到的就是来自于发出ping命令的那台机器的“询问”。  
   
  如果你的原意是只抓取来自61.149.185.201地址机器的数据(比如你向61.149.185.201发出ping命令,然后接收来自61.149.185.201的反馈),那么就不应该调用bind()函数,而应该调用connect()函数了。  
   
  之所以“源IP地址和目的IP地址老是一样的”,我想有两种可能,一种就是你在自己的机器(61.149.185.201)上ping自己的地址(61.149.185.201),这样源IP和目的IP自然是一样的。不过我想你不会犯这种低级错误。  
  第二种可能就是61.149.185.201这个地址是另外一台机器的地址,而你用bind()函数绑定别人的ip地址是什么意思呢?其结果就是相当于你根本没有调用bind(),而在不指定local   address(通过bind函数)的情况下,不管网络上(仅限于你所处的局域网)正在传输的包是不是发送给你的,你都会“慷慨接纳”,无单也照收。而如果这个时候恰巧没人给你发送包,而你自己却在向外发送包的话,那么你就会只收到自己发送出去的包。于是,源IP和目的IP就一样了。  
   
  套接字类型SOCK_STREAM下的bind()函数和SOCK_RAW类型下的bind()函数行为是不一样的。Top

8 楼mostideal(三甲)回复于 2005-05-05 01:50:30 得分 0

studyTop

9 楼bubugo()回复于 2005-05-05 08:55:17 得分 0

foxwing   你好,多谢你回答我的问题。但是还有些不明白希望您指教  
   
  char   *PacketDecode::GetLocateIP()                                                                                 //源IP地址  
  {  
  //inet_ntoa(*(in_addr*)&(ih->saddr));  
  //printf("\nsaddr:%d\n",ih->saddr);  
  return   inet_ntoa(*(in_addr*)&(ih->saddr));  
  }  
   
  char   *PacketDecode::GetRemoteIP()                                                                                 //目的地址(本机)  
  {        
  //printf("\ndaddr:%d\n",ih->daddr);  
  return   inet_ntoa(*(in_addr*)&(ih->daddr));  
  }  
   
  中读出的ih->saddr是不同的,但是为什么return到Getlocate就和Remote一样了那?  
  而且我用sniffer和我的程序同时开除了源IP这一项其他的都是一样的,就是源IP老是不对。希望您指教,谢谢  
  Top

10 楼foxwing(穿过你的骨髓我的手)回复于 2005-05-05 17:11:41 得分 15

把main()函数中的  
                n.a2=p.GetLocateIP();  
                printf("LocateIP:%ld\n",p.GetLocateIP());  
   
                n.a1=p.GetRemoteIP();  
                printf("RemoteIP:%ld\n",n.a1);  
  改为:  
                n.a2=p.GetLocateIP();  
                printf("LocateIP:%s\n",p.GetLocateIP());  
   
                n.a1=p.GetRemoteIP();  
                printf("RemoteIP:%s\n",n.a1);  
  就正常了。  
  因为inet_ntoa()函数返回的是一个字符串。Top

11 楼foxwing(穿过你的骨髓我的手)回复于 2005-05-05 17:18:20 得分 0

不要随便使用强制转型。Top

12 楼bubugo()回复于 2005-05-06 07:05:01 得分 0

谢谢foxwing,真的学了不少东西。  
  多谢,^_^Top

13 楼bubugo()回复于 2005-05-06 07:26:01 得分 0

再请教一下:我的IP都文件定义是  
  typedef   struct   ip_header  
  {//   IPv4   包头    
  unsigned   char ver_ihl; //   版本   (4   bits)   +   包头长度(4   bits)  
  unsigned   char tos; //   服务类型    
  unsigned   short     total_len; //   数据包的总长度    
  unsigned   short     id;                           //   ID号  
  unsigned   short     flag_offset; //   标志   (3   bits)   +   分片偏移   (13   bits)  
  unsigned   char ttl; //   生存时间  
  unsigned   char proto; //   协议  
  unsigned   short     checksum; //校验  
  unsigned   int saddr;                         //   源地址  
  unsigned   int daddr;                         //   目的地址  
  unsigned   int         opt;                                         //IP选项和填充  
  }IP_HEADER;  
   
  麻烦foxwing能不能帮我写个packetdecode中抓ttl,id   ,和flag_offset的代码呢?  
  我写了写总是抓不出了,感激中,呵呵。谢谢Top

14 楼foxwing(穿过你的骨髓我的手)回复于 2005-05-06 20:09:17 得分 0

int   PacketDecode::GetTTL()  
  {  
  int   i;  
  i   =   (int)ih->ttl;  
  return   i;  
  }  
   
  其它的函数都和这个差不多,我用ping命令测试过了,程序的结果和实际的TTL是一样的。  
   
  还有,你的main()函数里为什么不用cout呢?既然都用到类了,那为什么不用C++的iostream呢?Top

15 楼chd352622(Taiwan省委书记兼人大主任)回复于 2005-05-06 20:22:57 得分 0

gao   shou   a----Top

16 楼bubugo()回复于 2005-05-07 08:08:12 得分 0

呵呵,习惯了C语言了,有时就顺手写了,见笑了,多谢啦Top

相关问题

关键词

  • 数据
  • 协议
  • 函数
  • ip
  • 路由器
  • 因特网
  • packetdecode
  • 数据报
  • 地址
  • ih

得分解答快速导航

  • 帖主:bubugo
  • xuzheng318
  • foxwing

相关链接

  • C/C++ Blog
  • C/C++类图书
  • C/C++类源码下载

广告也精彩

反馈

请通过下述方式给我们反馈
反馈
提问
网站简介|广告服务|VIP资费标准|银行汇款帐号|网站地图|帮助|联系方式|诚聘英才|English|问题报告
北京创新乐知广告有限公司 版权所有, 京 ICP 证 070598 号
世纪乐知(北京)网络技术有限公司 提供技术支持
Copyright © 2000-2008, CSDN.NET, All Rights Reserved
GongshangLogo