`
tqx507tt
  • 浏览: 10600 次
最近访客 更多访客>>
社区版块
存档分类
最新评论

NAT检测的类

 
阅读更多

NAT检测的类
2010年09月10日
  // NatCheck.cpp : Defines the entry point for the console application.
  // #include "stdafx.h"    
  #include    
  #include     
  #include 
  #include "winsock2.h" 
  #include "./Include/packet.h"
  #pragma comment(lib,"./lib/wininet.lib")  
  #pragma comment(lib,"wsock32.lib")  
  #include "ws2tcpip.h"  
  #include "string.h"   #define N_SuperNode 5 #define N_NatCheckRequestQueue 20
  #define PORT_SERVER_NATCHECK 8888 
  #define PORT_SERVER_NATCHECK_1 8889
  #define PORT_CLIENT_NATCHECK 7777 
  #define PORT_SERVER_CLIENT_INFO 4444
  #define N_CheckTime 5 //最多检测次数 
  SOCKET sClient,sServer;//客户端和服务端的socket号
  struct sockaddr_in sn1_addr,sn2_addr,sn_addr,client_addr; 
  struct sockaddr_in client_addr_deal;
  struct in_addr in_addr_tmp,in_addr_tmp1;
  FILE *fp; //客户端读取hostcache.txt文件指针
  int i=0,j=0;
  unsigned long int snIP[N_SuperNode];//读取的SN的IP地址列表 
  unsigned short int snPort[N_SuperNode];//读取的SN的Port列表 
  char tmpIP[15],tmpPort[5];
  char ch;
  char IP_return[15];
  /* 本client的网络类型:
  * 0 = public net
  * 1 = full cone nat
  * 2 = symmetric nat
  * 3 = restricted cone nat
  * 4 = port restricted cone nat
  */
  unsigned long int myID=0,friendID=26;//本client和friend的用户ID
  char myNetType=-1,friendNetType=-1;
  unsigned long int myPubIp,friendPubIp,myPriIp,friendPriIp;
  unsigned short int myPubPort,friendPubPort,myPriPort,friendPriPort; 
  //natCheck请求包结构
  struct natCheckPacket{
  char version;
  char dowhat;
  unsigned short int port;
  unsigned long int ip;
  unsigned long int id;
  }natCheckPacket;
  typedef struct natCheckPacket NCP;
  char buff[sizeof(natCheckPacket)];//发包用的缓冲区
  //natCheck请求数据结构
  struct natCheckRequest{
  NCP ncp;//缓存到来的请求包
  struct natCheckRequest * next;//指向下一个请求数据
  unsigned long int ip;//发送请求的client IP地址
  unsigned short int port;//发送请求的client Port
  }natCheckRequest;
  typedef struct natCheckRequest NCR;
  struct netInfoResponsePacket{
  NCP ncp;
  unsigned long int ip_pub;
  unsigned short int port_pub;
  unsigned short int no; 
  }netInfoResponsePacket;
  typedef struct netInfoResponsePacket NIRP;
  //natCheck请求数据循环队列
  NCR natCheckRequestQueue[N_NatCheckRequestQueue];
  NCR * h_NatCheckRequestQueue,* t_NatCheckRequestQueue;
  /*
  * 获得本地主机IP地址
  */
  char * getownIP()
  {
  //////////////////   
  //   获得主机名.    
  char   hostname[256];   
  int   res   =   gethostname(hostname,   sizeof(hostname));   
  if   (res   !=   0)   {   
  printf("Error:   %u\n",   WSAGetLastError());   
  return "failed";   
  }     
  ////////////////   
  //   根据主机名获取主机信息.   
  hostent*   pHostent   =   gethostbyname(hostname);   
  if   (pHostent==NULL)   {   
  printf("Error:   %u\n",   WSAGetLastError());   
  return   "failed";   
  }   
  //////////////////   
  //   解析返回的hostent信息.    
  hostent&   he   =   *pHostent;   
  sockaddr_in   sa;   
  memcpy   (   &sa.sin_addr.s_addr,   he.h_addr_list[0],he.h_length);   
  return inet_ntoa(sa.sin_addr);   
  }
  unsigned long int getownIP_uli()
  {
  //////////////////   
  //   获得主机名.    
  char   hostname[256];   
  int   res   =   gethostname(hostname,   sizeof(hostname));   
  if   (res   !=   0)   {   
  printf("Error:   %u\n",   WSAGetLastError());   
  return -1;   
  }     
  ////////////////   
  //   根据主机名获取主机信息.   
  hostent*   pHostent   =   gethostbyname(hostname);   
  if   (pHostent==NULL)   {   
  printf("Error:   %u\n",   WSAGetLastError());   
  return   -1;   
  }   
  //////////////////   
  //   解析返回的hostent信息.    
  hostent&   he   =   *pHostent;   
  sockaddr_in   sa;   
  memcpy   (   &sa.sin_addr.s_addr,   he.h_addr_list[0],he.h_length);   
  return sa.sin_addr.S_un.S_addr;
  }
  /*
  * superNode接收请求线程入口函数
  */
  unsigned int _stdcall ThreadFunction_sn_get(void *param)
  {
  //创建套接字
  if( (sServer = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) SOCKET号失败!!!\n");
  return 0;
  }
  //绑定套接字和本机地址和端口  
  sn_addr.sin_family=AF_INET;
  sn_addr.sin_port=htons(PORT_SERVER_NATCHECK); 
  sn_addr.sin_addr.s_addr =INADDR_ANY ;//inet_addr(getownIP());  //
  if(bind(sServer, (struct sockaddr*)&sn_addr, sizeof(sn_addr)) SOCKET号上!!!\n");
  closesocket(sServer); 
  return 0;
  }
  //printf("接收....\n");
  int iLen=sizeof(client_addr); 
  struct natCheckPacket * ncp=(struct natCheckPacket *)buff; 
  int timeout=300; 
  while (1)
  {
  setsockopt(sServer, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,sizeof(timeout));
  if(recvfrom(sServer,buff,sizeof(buff),0,(sockaddr* )&client_addr,&iLen)!=-1)
  {
  //判断队列是否满
  if(t_NatCheckRequestQueue->next!=h_NatCheckRequestQ ueue)
  {
  //先修改t
  NCR * t=t_NatCheckRequestQueue;
  t_NatCheckRequestQueue=t->next;
  //再写入
  t->ncp=*(ncp);
  t->ip=client_addr.sin_addr.S_un.S_addr;
  t->port=client_addr.sin_port;
  }
  }
  Sleep(300);
  //printf("version:%d\tdowhat:%d\tport:%d\tip:%d\n" ,ncp->version,ncp->dowhat,
  // ncp->port,ncp->ip);
  //printf("Client said: %s\n",buff);
  //strcpy(buff,"I am a server!!\n");
  //sendto(sServer,buff,sizeof(buff),0,(sockaddr*)&c lient_addr,sizeof(client_addr));
  }  
  //closesocket(sServer);
  return 0;
  }
  /*
  * 构造NCP包发送给SuperNode 
  * 接受返回的NCP包
  */
  int sendNCPtoSNandRecvNCP(unsigned long int ip_SN,unsigned short int port_SN,
  NCP ncp_send)
  {
  int timeout=300;  
  sn_addr.sin_addr.S_un.S_addr=ip_SN;
  sn_addr.sin_family=AF_INET;
  sn_addr.sin_port=htons(port_SN);  
  int iLen=sizeof(sn_addr);
  NCP * ncp=(NCP *)buff;
  ncp->version=ncp_send.version;
  ncp->dowhat=ncp_send.dowhat;
  ncp->port=ncp_send.port;
  ncp->ip=ncp_send.ip; 
  ncp->id=ncp_send.id;
  setsockopt(sClient, SOL_SOCKET , SO_SNDTIMEO, (char *)&timeout,sizeof(timeout));
  sendto(sClient,buff,sizeof(buff),0,(SOCKADDR*)&sn_ addr,iLen); 
  in_addr_tmp.S_un.S_addr=ip_SN; 
  in_addr_tmp1.S_un.S_addr=ncp->ip;
  char * ipaddr=NULL;
  char addr[15];
  in_addr inaddr;
  inaddr. s_addr=ncp->ip;
  ipaddr= inet_ntoa(inaddr);
  strcpy(addr,ipaddr); 
  printf("[send][SN(%s)]\n\tversion:%d\tdowhat:%d\tp ort:%d\tip:%s\n",inet_ntoa(in_addr_tmp),
  ncp->version,ncp->dowhat,ncp->port,addr);
  timeout=1500;
  setsockopt(sClient, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,sizeof(timeout));
  if(recvfrom(sClient,buff,sizeof(buff),0,(sockaddr* )&sn_addr,&iLen)ip; 
  printf("[rece][sn(%s)]\n\tversion:%d\tdowhat:%d\tp ort:%d\tip:%s\n",addr,((NCP *)buff)->version,
  ((NCP *)buff)->dowhat,ntohs(((NCP *)buff)->port),inet_ntoa(in_addr_tmp));
  return 1;
  }
  }
  /*
  * 构造NCP包发送给SuperNode
  * 接受返回的NIRP包
  */
  int sendNCPtoSNandRecvNIRP(unsigned long int ip_SN,unsigned short int port_SN,
  NCP ncp_send)
  {
  FILE * fp_n;
  FILE * fp_c;//for compare
  //打开文件natCheckResult.txt
  if(!(fp_n=fopen("./natCheckResult.txt","a")))
  {
  printf("natCheckResult.txt file not found!\n");
  return 0;
  } 
  char one_line[100],one_line_f[100];
  int timeout=300;  
  sn_addr.sin_addr.S_un.S_addr=ip_SN;
  sn_addr.sin_family=AF_INET;
  sn_addr.sin_port=htons(port_SN);  
  int iLen=sizeof(sn_addr);
  char buff_recv[sizeof(NIRP)];
  NCP * ncp=(NCP *)buff;
  NIRP * nirp=(NIRP *)buff_recv;
  ncp->version=ncp_send.version;
  ncp->dowhat=ncp_send.dowhat;
  ncp->port=ncp_send.port;
  ncp->ip=ncp_send.ip; 
  ncp->id=ncp_send.id;
  setsockopt(sClient, SOL_SOCKET , SO_SNDTIMEO, (char *)&timeout,sizeof(timeout));
  sendto(sClient,buff,sizeof(buff),0,(SOCKADDR*)&sn_ addr,iLen); 
  in_addr_tmp.S_un.S_addr=ip_SN; 
  in_addr_tmp1.S_un.S_addr=ncp->ip;
  char * ipaddr=NULL;
  char addr[15];
  in_addr inaddr;
  inaddr. s_addr=ncp->ip;
  ipaddr= inet_ntoa(inaddr);
  strcpy(addr,ipaddr); 
  printf("[send][SN(%s)]\n\tversion:%d\tdowhat:%d\tp ort:%d\tip:%s\n",
  inet_ntoa(in_addr_tmp),ncp->version,ncp->dowhat,ncp-> port,addr);
  timeout=1500;
  setsockopt(sClient, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,sizeof(timeout));
  int stop=0;
  while(!stop)
  {
  setsockopt(sClient, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,sizeof(timeout));
  if(recvfrom(sClient,buff_recv,sizeof(buff_recv),0, (sockaddr*)&sn_addr,&iLen)ncp.id,
  ((NIRP *)buff_recv)->ncp.dowhat,
  ((NIRP *)buff_recv)->ip_pub,
  ((NIRP *)buff_recv)->port_pub,
  ((NIRP *)buff_recv)->ncp.ip,
  ((NIRP *)buff_recv)->ncp.port); 
  printf("%s\n",one_line);
  friendNetType=((NIRP *)buff_recv)->ncp.dowhat;
  friendPubIp=((NIRP *)buff_recv)->ip_pub;
  friendPubPort=((NIRP *)buff_recv)->port_pub;
  friendPriIp=((NIRP *)buff_recv)->ncp.ip;
  friendPriPort=((NIRP *)buff_recv)->ncp.port;
  //打开文件natCheckResult.txt
  if(!(fp_c=fopen("./natCheckResult.txt","r")))
  {
  printf("natCheckResult.txt file not found!\n");
  return 0;
  } 
  while(!feof(fp_c))
  {
  i=0;
  while((ch=fgetc(fp_c))!=10 && ch!=-1)
  one_line_f[i++]=ch;
  if(ch==-1)
  break; 
  one_line_f[i]='\0'; 
  if(strcmp(one_line,one_line_f)==0)
  {
  fclose(fp_c);
  fclose(fp_n);
  return 1;
  }
  }
  fprintf(fp_n,"%s\n",one_line);
  fflush(fp_n);
  }
  }
  fclose(fp_c);
  fclose(fp_n);
  return 1;
  }
  void longIP2string(unsigned long int ip,char* addr)
  {
  in_addr inaddr;
  char * ipaddr=NULL;
  inaddr. s_addr=sn_addr.sin_addr.S_un.S_addr;
  ipaddr= inet_ntoa(inaddr);
  strcpy(addr,ipaddr); 
  }
  /*
  * 从client端的hostcache.txt文件获取一个SN
  *  写入ip_SN,port_SN
  *  如果文件已经到结尾,或者文件语法错误,则返回0
  */
  int getSNfromHostCache(FILE * fp,unsigned long int &ip_SN,unsigned short int &port_SN)
  {
  if(feof(fp))
  return 0;
  i=0;
  while((ch=fgetc(fp))!=' ' && ch!=10 && ch!=-1)
  tmpIP[i++]=ch;
  if(ch==10 || ch==-1)
  {
  printf("hostcache.txt file error!\n");
  return 0;
  }
  tmpIP[i]='\0';
  i=0;
  while((ch=fgetc(fp))!=10 && ch!=-1)
  tmpPort[i++]=ch;
  tmpPort[i]='\0';
  ip_SN=inet_addr(tmpIP);
  port_SN=(unsigned short int)atoi(tmpPort);
  return 1;
  }
  /*
  * client最先知道检测结果
  *  client需要向自己缓存的SN节点汇报自己的网络类型信息
  *  这里依然使用了NCP包
  void broadcastNatCheckResult(char version,
  char dowhat,unsigned long int ip,unsigned short int port,
  unsigned long int id)
  */
  void broadcastNatCheckResult(NCP ncp_send)
  {
  FILE * fp_b=fp;
  fseek(fp_b,0L,0);
  while (!feof(fp_b)) {
  i=0;
  while((ch=fgetc(fp_b))!=' ' && ch!=10 && ch!=-1)
  tmpIP[i++]=ch;
  if(ch==10 || ch==-1)
  {
  printf("hostcache.txt file error!\n");
  return;
  }
  tmpIP[i]='\0';
  i=0;
  while((ch=fgetc(fp_b))!=10 && ch!=-1)
  tmpPort[i++]=ch;
  tmpPort[i]='\0'; 
  int timeout=300;
  sn_addr.sin_addr.S_un.S_addr=inet_addr(tmpIP);
  sn_addr.sin_family=AF_INET;
  sn_addr.sin_port=htons((unsigned short int)atoi(tmpPort)); 
  int iLen=sizeof(sn_addr);
  NCP * ncp=(NCP *)buff;
  ncp->version=ncp_send.version;
  ncp->dowhat=ncp_send.dowhat;
  ncp->port=ncp_send.port;
  ncp->ip=ncp_send.ip; 
  ncp->id=ncp_send.id;
  setsockopt(sClient, SOL_SOCKET , SO_SNDTIMEO, (char *)&timeout,sizeof(timeout));
  sendto(sClient,buff,sizeof(buff),0,(SOCKADDR*)&sn_ addr,iLen); 
  }
  fclose(fp_b);
  return;
  }
  /*
  * SN收到client汇报的结果,
  * 向NatCheckResult.txt 写入id 网络类型 外网ip port 内网ip port 
  */
  int storeNatCheckResult(unsigned long int id,char type,
  unsigned long int pub_ip,unsigned short int pub_port,
  unsigned long int pri_ip,unsigned short int pri_port)
  {
  FILE * fp_n;
  char one_line[100],one_line_f[100];
  sprintf(one_line,"%u %u %u %u %u %u",id,type,pub_ip,pub_port,pri_ip,pri_port);
  //打开文件natCheckResult.txt
  if(!(fp_n=fopen("./natCheckResult.txt","rw")))
  {
  printf("natCheckResult.txt file not found!\n");
  return 0;
  } 
  while(!feof(fp_n))
  {
  i=0;
  while((ch=fgetc(fp_n))!=10 && ch!=-1)
  one_line_f[i++]=ch;
  if(ch==-1)
  {
  break;
  }
  one_line_f[i]='\0'; 
  if(strcmp(one_line,one_line_f)==0)
  return 0;
  }
  fclose(fp_n);
  if(!(fp_n=fopen("./natCheckResult.txt","a")))
  {
  printf("natCheckResult.txt file not found!\n");
  return 0;
  }  
  fprintf(fp_n,"%u %u %u %u %u %u\n",id,type,pub_ip,pub_port,pri_ip,pri_port); 
  printf("%u %u %u %u %u %u\n",id,type,pub_ip,pub_port,pri_ip,pri_port); 
  fflush(fp_n); 
  fclose(fp_n);
  return 1;
  }
  /*
  * SN收到client的查询请求,
  * 从NatCheckResult.txt 中查找id对应的 网络类型 外网ip port 内网ip port 
  */
  int searchNatCheckResult(NCP ncp,SOCKET sServer,sockaddr_in addr)
  {
  FILE * fp_n;
  char id[32];
  //打开文件natCheckResult.txt
  if(!(fp_n=fopen("./natCheckResult.txt","r")))
  {
  printf("natCheckResult.txt file not found!\n");
  return 0;
  } 
  int j=0;
  while(!feof(fp_n))
  {
  i=0;
  while((ch=fgetc(fp_n))!=' ' && ch!=10 && ch!=-1)
  id[i++]=ch;
  if(ch==10)
  {
  printf("natCheckResult.txt file error!\n");
  return 0;
  }
  if(ch==-1)
  {
  break;
  }
  id[i]='\0'; 
  if(ncp.id!=(unsigned long int)atoi(id))
  {
  while(fgetc(fp_n)!=10);
  continue;
  }
  unsigned long int ip_pub;
  unsigned short int port_pub;
  fscanf(fp_n,"%d %d %d %d %d\n",&(ncp.dowhat),&ip_pub,&port_pub,&(ncp.ip),&( ncp.port)); 
  char buff_send[sizeof(NIRP)];
  NIRP * nirp = (NIRP *) buff_send;
  nirp->ncp=ncp;
  nirp->ip_pub=ip_pub;
  nirp->port_pub=port_pub;
  nirp->no=j++;  
  sendto(sServer,buff_send,sizeof(buff_send),0,(sock addr*)&addr,sizeof(addr)); 
  } 
  fclose(fp_n);
  return 1;
  }
  /*
  * main函数
  */
  int main(int argc, char* argv[])
  {   
  if(argc =3)
  myID=atoi(argv[2]);
  NCP ncp_send;
  ncp_send.version=0; 
  ncp_send.id=myID; 
  //////////////////
  //  读取hostcache文件中的前两个supernode
  if(!(fp=fopen("./hostcache.txt","r")))
  {
  printf("hostcache.txt file not found!\n");
  return 0;
  }
  if( (sClient=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP)) SOCKET号失败!!!\n");
  return 0;
  }  
  myPriIp=inet_addr(getownIP());
  myPriPort=htons(PORT_CLIENT_NATCHECK); 
  client_addr.sin_addr.S_un.S_addr=INADDR_ANY; /* use my IP address */
  client_addr.sin_family=AF_INET;
  client_addr.sin_port=htons(PORT_CLIENT_NATCHECK);
  printf("[info]client ip=%s\tport:%d\n",getownIP(),ntohs(myPriPort));
  //bind(int sockfd, const struct sockaddr *my_addr, int addrlen);
  if(bind(sClient,(struct sockaddr*)&client_addr,sizeof(client_addr))SOCKET号上!!!\n");
  closesocket(sClient); 
  return 0;
  }
  /*//////////////////////////////////////////////// /////////////////////////////////////
  // NAT检测开始
  // 检测流程:
  1.向超级节点SN1发送0号包,等待一段超时时间,如果没有返回,换下一个超级节点。
  否则go 2,如果hostcache中的节点都失效了,那么开始向中心节点发请求,来得到一批
  新的superNode节点列表;
  2.判断超级节点返回的7号包中携带的(ip,port)和自己发包时用的(ip,port)是否相同,
  如果相同的话,说明本地是公网IP;如果不同的话,说明在NAT后;
  3.向SN1发送1号包,并携带一个自己列表中的另一个superNode,SN2的(ip,port),让SN1
  发8号包给SN2,告诉本client的外网(ip,port),让SN2给本client发6号包;另外SN1还可
  以在自己维护的临近的SN列表中选择3个也给client发送6号包。
  4.如果client在一段超时时间内,没有收到任何包,那么在将3中的过程进行一次,总共最多
  可以进行N_CheckTime(5)次。其中只要有一次收到包,就go 5。
  5.如果收到了SN2、SN3、SN4中的任何一个,检测就停止,结果是full cone Nat。如果没有
  收到任何包,检测继续,go 6
  6.client从自己的hostcache中选择一个SN2,向其发送2号包,等待一段超时时间,如果没有
  收到5号包的话,继续从hostcache中另选择一个SN3,如果hostcache中的所有SN都不给回应
  5号包的话,从中心节点获取新的SN后,继续发2号包。收到第一个5号包,开始比较,如果和
  SN1的返回结果(ip,port)中如果有任何一对不一致,则说明是Symmetric NAT,检测停止。
  否则是Restricted Cone NAT,同时继续检测,go 7
  7.client向SN1发送3号包,让SN1换用另一个端口发4号包,重复若干次,如果client能收到说明
  是Restricted Cone NAT,否则是Port Restricted Cone NAT。检测结束。
  *///////////////////////////////////////////////// //////////////////////////////////////
  //读取第一个SN,SN1的(IP,Port),并给其发0号包
  if(getSNfromHostCache(fp,snIP[0],snPort[0])==0)
  {
  printf("[error]there is no SN in HostCache.txt!\n");
  return 0;
  }
  /*
  int sendNCPtoSNandRecvNCP(unsigned long int ip_SN,
  unsigned short int port_SN,
  char version,
  char dowhat,
  unsigned long int ip,
  unsigned short int port) 
  */ 
  ncp_send.dowhat=0; 
  ncp_send.ip=0; 
  ncp_send.port=0;  
  while(sendNCPtoSNandRecvNCP(snIP[0],snPort[0],ncp_ send)==0)
  {
  if(getSNfromHostCache(fp,snIP[0],snPort[0])==0)
  {
  printf("[error]there is no more SN in HostCache.txt!\n");
  //此时应该从中心节点获取更新的SN列表
  //......
  printf("[error]check failed temporarily");
  return 0;
  }
  } 
  long ft=ftell(fp);
  in_addr_tmp.S_un.S_addr=snIP[0]; 
  printf("[info]SN1 ip=%s\tport=%d\n",inet_ntoa(in_addr_tmp),snPort[0] );
  //对比返回的(ip,port) ip_return port_return
  unsigned long int ip_return=((NCP *)buff)->ip;
  unsigned short int port_return=((NCP *)buff)->port;
  if(myPriIp==ip_return && myPriPort==port_return)
  {
  printf("[Reslut]public net\n"); 
  myNetType=0;
  ncp_send.dowhat=9; 
  ncp_send.ip=myPubIp=myPriIp; 
  ncp_send.port=myPubPort=myPriPort; 
  broadcastNatCheckResult(ncp_send);
  return 0;
  }
  //再读取一个SN,SN2的(IP,Port)
  int checkTime=N_CheckTime;
  while(checkTime>0 && !feof(fp))
  {
  if(getSNfromHostCache(fp,snIP[1],snPort[1])==0)
  {
  printf("[error]there is no more SN in HostCache.txt!\n");
  break;
  }  
  ncp_send.dowhat=1; 
  ncp_send.ip=snIP[1]; 
  ncp_send.port=snPort[1]; 
  if(sendNCPtoSNandRecvNCP(snIP[0],snPort[0],ncp_sen d)==1)
  {  
  printf("[Reslut]full cone nat\n");
  myNetType=1;
  ncp_send.dowhat=10; 
  ncp_send.ip=myPriIp; 
  ncp_send.port=myPriPort;
  myPubIp=ip_return;
  myPubPort=port_return;
  broadcastNatCheckResult(ncp_send);
  return 0;
  }  
  checkTime--;
  }
  printf("[Reslut]not full cone nat, checking is continued.\n");
  in_addr_tmp.S_un.S_addr=snIP[1]; 
  printf("[info]SN2 ip=%s\tport=%d\n",inet_ntoa(in_addr_tmp),snPort[1] );  
  //在hostcache中的SN1下再找一个SN3,给他发送2号包,让他返回client的ip和port
  fseek(fp,ft,0);
  if(getSNfromHostCache(fp,snIP[1],snPort[1])==0)
  {
  printf("[error]there is no SN in HostCache.txt!\n");
  return 0;
  }  
  ncp_send.dowhat=2; 
  ncp_send.ip=0; 
  ncp_send.port=0;  
  while(sendNCPtoSNandRecvNCP(snIP[1],snPort[1],ncp_ send)==0)
  {
  if(getSNfromHostCache(fp,snIP[1],snPort[1])==0)
  {
  printf("[error]there is no more SN in HostCache.txt!\n");
  //此时应该从中心节点获取更新的SN列表
  //......
  printf("[error]check failed temporarily");
  return 0;
  }
  } 
  in_addr_tmp.S_un.S_addr=snIP[1]; 
  printf("[info]SN3 ip=%s\tport=%d\n",inet_ntoa(in_addr_tmp),snPort[1] );
  //对比返回的(ip,port) ip_return port_return
  unsigned long int ip_return1=((NCP *)buff)->ip;
  unsigned short int port_return1=((NCP *)buff)->port;
  if(ip_return1!=ip_return || port_return1!=port_return)
  {
  printf("[Reslut]symmetric nat\n");
  myNetType=2;
  ncp_send.dowhat=11; 
  ncp_send.ip=myPriIp; 
  ncp_send.port=myPriPort; 
  broadcastNatCheckResult(ncp_send);
  return 0;
  }  
  ncp_send.dowhat=3; 
  ncp_send.ip=0; 
  ncp_send.port=0;  
  if(sendNCPtoSNandRecvNCP(snIP[0],snPort[0],ncp_sen d)==1)
  {
  printf("[Reslut]Restricted Cone nat\n");
  myNetType=3;
  ncp_send.dowhat=12; 
  ncp_send.ip=myPriIp; 
  ncp_send.port=myPriPort; 
  myPubIp=ip_return;
  myPubPort=port_return;
  broadcastNatCheckResult(ncp_send);
  return 0;
  }
  printf("[Reslut]Port Restricted Cone nat\n");
  myNetType=4;
  ncp_send.dowhat=13; 
  ncp_send.ip=myPriIp; 
  ncp_send.port=myPriPort;
  myPubIp=ip_return;
  myPubPort=port_return;
  broadcastNatCheckResult(ncp_send);
  //以上检测网络类型结束,下面开始与某好友通讯
  printf("do you want to talk with someone? [Y]yes [N]no\n");
  scanf("%c",&ch);
  if(ch!='Y' && ch!='y')
  return 0;
  printf("which friend would you want to talk with? Input his id:\n");
  scanf("%d",&friendID);
  //从SN1获取friend网络类型列表
  ncp_send.dowhat=14; 
  ncp_send.ip=0; 
  ncp_send.port=0;
  ncp_send.id=friendID;
  if(sendNCPtoSNandRecvNIRP(snIP[0],snPort[0],ncp_se nd)==0)
  {  
  printf("[error]查询好友网络信息失败!\n");
  return 0;
  }
  switch(friendNetType)
  {
  case 9:
  break;
  case 10:
  break;
  case 11:
  break;
  case 12:
  break;
  case 13:
  break;
  default:
  break;
  }
  }
  ////////////////////////////////////////////////// //////////////////
  //服务端程序入口
  ////////////////////////////////////////////////// ///////////////////
  else if(strcmp(argv[1],"-s")==0)
  {
  //创建另一个套接字
  SOCKET sServer1;
  if( (sServer1 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) SOCKET号失败!!!\n");
  return 0;
  }
  //绑定套接字和本机地址和端口  
  sn1_addr.sin_family=AF_INET;
  sn1_addr.sin_port=htons(PORT_SERVER_NATCHECK_1); 
  sn1_addr.sin_addr.s_addr =INADDR_ANY ;//inet_addr(getownIP());  //
  if(bind(sServer1, (struct sockaddr*)&sn1_addr, sizeof(sn1_addr)) SOCKET号上!!!\n");
  closesocket(sServer1); 
  return 0;
  }
  //////////////////
  //  循环队列natCheckRequestQueue初始化
  for(i=0;incp;
  unsigned long int ip_deal=h_NatCheckRequestQueue->ip;
  unsigned short int port_deal=h_NatCheckRequestQueue->port;
  //再修改h
  h_NatCheckRequestQueue=h_NatCheckRequestQueue->next ;
  //处理这个来自(ip,port)的请求  
  switch(ncp_deal->dowhat)
  {
  /* dowhat字段: 
  *   0 请求用户返回Ip:port   7 单独的响应包
  *   1 客户请求提供其他主机检测  6 其他主机响应包
  *   2 同时请求两主机发回响应  5 针对2的回应包
  *   3 请求使用另一端口发回响应  4 使用另一端口响应 
  *   8 SN请求其他主机检测
  -------------------------------------------------- ---------
  *  9  汇报检测结果给SN public net
  *  10 汇报检测结果给SN full cone nat
  *  11 汇报检测结果给SN symmetric nat
  *  12 汇报检测结果给SN restricted cone nat
  *  13 汇报检测结果给SN port restricted cone nat
  -------------------------------------------------- ---------
  */
  case 0:
  ncp_deal->dowhat=7;
  ncp_deal->ip=ip_deal;
  ncp_deal->port=port_deal; 
  client_addr_deal.sin_family=AF_INET;
  client_addr_deal.sin_addr.S_un.S_addr=ip_deal;
  client_addr_deal.sin_port=port_deal;
  printf("[deal][0]send [7] to:%d.%d.%d.%d:%d\n",
  client_addr_deal.sin_addr.S_un.S_un_b.s_b1,
  client_addr_deal.sin_addr.S_un.S_un_b.s_b2,
  client_addr_deal.sin_addr.S_un.S_un_b.s_b3,
  client_addr_deal.sin_addr.S_un.S_un_b.s_b4,
  htons(client_addr_deal.sin_port));
  sendto(sServer,buff,sizeof(buff),0,(sockaddr*)&cli ent_addr_deal,sizeof(client_addr_deal)); 
  break;
  case 1: 
  client_addr_deal.sin_family=AF_INET;
  client_addr_deal.sin_addr.S_un.S_addr=ncp_deal->ip;
  client_addr_deal.sin_port=htons(ncp_deal->port);
  ncp_deal->dowhat=8;
  ncp_deal->ip=ip_deal;
  ncp_deal->port=port_deal;
  printf("[deal][1]send [8] to:%d.%d.%d.%d:%d\n",
  client_addr_deal.sin_addr.S_un.S_un_b.s_b1,
  client_addr_deal.sin_addr.S_un.S_un_b.s_b2,
  client_addr_deal.sin_addr.S_un.S_un_b.s_b3,
  client_addr_deal.sin_addr.S_un.S_un_b.s_b4,
  htons(client_addr_deal.sin_port));     
  sendto(sServer,buff,sizeof(buff),0,(sockaddr*)&cli ent_addr_deal,sizeof(client_addr_deal)); 
  break;
  case 2:
  client_addr_deal.sin_family=AF_INET;
  client_addr_deal.sin_addr.S_un.S_addr=ip_deal;
  client_addr_deal.sin_port=port_deal;
  ncp_deal->dowhat=5;
  ncp_deal->ip=ip_deal;
  ncp_deal->port=port_deal;
  printf("[deal][2]send [5] to:%d.%d.%d.%d:%d\n",
  client_addr_deal.sin_addr.S_un.S_un_b.s_b1,
  client_addr_deal.sin_addr.S_un.S_un_b.s_b2,
  client_addr_deal.sin_addr.S_un.S_un_b.s_b3,
  client_addr_deal.sin_addr.S_un.S_un_b.s_b4,
  htons(client_addr_deal.sin_port));     
  sendto(sServer,buff,sizeof(buff),0,(sockaddr*)&cli ent_addr_deal,sizeof(client_addr_deal)); 
  break;
  case 3:
  client_addr_deal.sin_family=AF_INET;
  client_addr_deal.sin_addr.S_un.S_addr=ip_deal;
  client_addr_deal.sin_port=port_deal;
  ncp_deal->dowhat=4;
  ncp_deal->ip=ip_deal;
  ncp_deal->port=port_deal;
  printf("[deal][3]send [4] to:%d.%d.%d.%d:%d\n",
  client_addr_deal.sin_addr.S_un.S_un_b.s_b1,
  client_addr_deal.sin_addr.S_un.S_un_b.s_b2,
  client_addr_deal.sin_addr.S_un.S_un_b.s_b3,
  client_addr_deal.sin_addr.S_un.S_un_b.s_b4,
  htons(client_addr_deal.sin_port));     
  sendto(sServer1,buff,sizeof(buff),0,(sockaddr*)&cl ient_addr_deal,sizeof(client_addr_deal)); 
  break; 
  case 8:
  ncp_deal->dowhat=6; 
  client_addr_deal.sin_family=AF_INET;
  client_addr_deal.sin_addr.S_un.S_addr=ncp_deal->ip;
  client_addr_deal.sin_port=htons(ncp_deal->port);
  ncp_deal->ip=getownIP_uli();
  ncp_deal->port=htons(PORT_SERVER_NATCHECK);
  printf("[deal][8] send[6] to:%d.%d.%d.%d:%d\n",
  client_addr_deal.sin_addr.S_un.S_un_b.s_b1,
  client_addr_deal.sin_addr.S_un.S_un_b.s_b2,
  client_addr_deal.sin_addr.S_un.S_un_b.s_b3,
  client_addr_deal.sin_addr.S_un.S_un_b.s_b4,
  htons(client_addr_deal.sin_port));
  sendto(sServer,buff,sizeof(buff),0,(sockaddr*)&cli ent_addr_deal,sizeof(client_addr_deal)); 
  break; 
  case 9:
  //写入id 网络类型 外网ip port 内网ip port  
  storeNatCheckResult(ncp_deal->id,
  ncp_deal->dowhat,ip_deal,port_deal,
  ncp_deal->ip,ncp_deal->port);
  printf("[deal][9] writing file\n");
  break;
  case 10:
  //写入id 网络类型 外网ip port 内网ip port 
  storeNatCheckResult(ncp_deal->id,
  ncp_deal->dowhat,ip_deal,port_deal,
  ncp_deal->ip,ncp_deal->port);
  printf("[deal][10] writing file\n");
  break;
  case 11:
  //写入id 网络类型 外网ip port 内网ip port 
  storeNatCheckResult(ncp_deal->id,
  ncp_deal->dowhat,ip_deal,port_deal,
  ncp_deal->ip,ncp_deal->port);
  printf("[deal][11] writing file\n");
  break;
  case 12:
  //写入id 网络类型 外网ip port 内网ip port 
  storeNatCheckResult(ncp_deal->id,
  ncp_deal->dowhat,ip_deal,port_deal,
  ncp_deal->ip,ncp_deal->port);
  printf("[deal][12] writing file\n");
  break;
  case 13:
  //写入id 网络类型 外网ip port 内网ip port  
  storeNatCheckResult(ncp_deal->id,
  ncp_deal->dowhat,ip_deal,port_deal,
  ncp_deal->ip,ncp_deal->port);
  printf("[deal][13] writing file\n"); 
  break;
  case 14:
  //处理client发来的查询请求
  //查询id对应用户的网络信息  
  client_addr_deal.sin_family=AF_INET;
  client_addr_deal.sin_addr.S_un.S_addr=ip_deal;
  client_addr_deal.sin_port=port_deal;
  printf("[deal][14]send [15] to:%d.%d.%d.%d:%d\n",
  client_addr_deal.sin_addr.S_un.S_un_b.s_b1,
  client_addr_deal.sin_addr.S_un.S_un_b.s_b2,
  client_addr_deal.sin_addr.S_un.S_un_b.s_b3,
  client_addr_deal.sin_addr.S_un.S_un_b.s_b4,
  htons(client_addr_deal.sin_port));
  searchNatCheckResult(*ncp_deal,sServer,client_addr _deal); 
  break;
  default:
  break;
  }
  }
  Sleep(300);
  }  
  } 
  //////////////////   
  //   终止   Windows   sockets   API   
  WSACleanup();  
  return 0;
  }
分享到:
评论

相关推荐

    NAT类型检测

    自动检测NAT类型,自动检测NAT类型,自动检测NAT类型,自动检测NAT类型,自动检测NAT类型,自动检测NAT类型,自动检测NAT类型,自动检测NAT类型。

    windows 系统NAT类型检测工具

    windows 系统NAT类型检测工具

    NAT检测工具.zip

    检测本地网络nat类型,方便开发不同类型p2p

    NAT穿透之NAT类型检测.pdf

    NAT穿透之NAT类型检测 NAT穿透之NAT类型检测

    NAT类型检测工具

    NAT类型检测工具 直接运行,相当好用,但要有.NET 2.0以上的环境支持,也就是说,要安装VC++ 6.0或VS,如果不想用这个工具的话,还有个在线网址,大家可以看一下,不过还是要下载JAVA虚拟机: ...

    nat类型检测工具

    NAT类型检测,亲测可用。NAT 检测最实用的工具。p2p必备软件

    NAT检测程序

    本程序分为:UDP服务器与UDP客户端。服务器运行在公网上且绑定两个公网IP;客户端运行在本地。 可检测的NAT类型包括: 1. 完全锥形 NAT 2. 限制锥形 NAT 3. 端口限制锥形 NAT 4. 对称 NAT

    NAT检测技术分析及应用

    小型路由器的普及,在给用户带来极大方便的同时,也给园区网络带来了各类安全隐患。通过NAT检测技术查找定位NAT设备,消除网络...文章对各种NAT检测技术的进行了分析,提出并实现校园网网络环境下NAT检测技术的应用方法。

    NAT检测

    刚刚完成的一个程序本程序可以完成对本地NAT设备类型的检测。需要.netformwork1.1 类库支持.

    NAT类型检测工具 windows版

    一个用户检测本地网络NAT类型的windows工具; 原程序使用python编写,之后打包为.exe ,命令行执行。 下载后解压,命令行进入解压后目录,执行pystun.exe即可看到帮助与参数示例。 执行结果为 NAT类型,外部显示的IP...

    自动NAT检测STUN源代码.rar_nat stun_nat 类型_nat在线检测_nat检测_网络类型

    可以自动探测你所处的网络NAT类型

    NAT类型检测+免费的STUN服务器.rar

    P2P技术的NAT穿越方案,需要针对上述的4种NAT类型使用不同的方案,才有可能打洞(穿墙)成功,而最在要紧的是,我该怎么知道目前某台客户端所处的路由属于哪种NAT类型呢?

    一个NAT类型检测方案

    NAT实现大致可分为Full Cone、Restricted Cone、Port Restricted Cone和Symmetric NAT四种,本文档是自己根据对NAT的理解,写的一个测试NAT方案。

    nat穿透测试工具

    nat穿透辅助测试工具,方便侦察自身nat类型,便捷好用。

    介绍5种 socket P2P NAT类型检测方法.zip

    介绍5种 P2P socket NAT类型检测方法.zip

    p2p网络穿越中nat类型检测的原理与实现.pdf

    p2p网络穿越中nat类型检测的原理与实现.pdfp2p网络穿越中nat类型检测的原理与实现.pdfp2p网络穿越中nat类型检测的原理与实现.pdfp2p网络穿越中nat类型检测的原理与实现.pdfp2p网络穿越中nat类型检测的原理与实现.pdf

    tcp udp nat检测工具最新版本

    tcp udp nat检测工具最新版本 可以实时检测您当前tcp udp是否正常 也可以检测你的nat状态 如果玩外服游戏,出现nat严格,gta5无法线上等 可以用这个查看下自己网络状态。 解压密码:123

    NAT类型测试的小工具

    NAT类型测试工具,检查判断自己或对方的nat类型。公开的免费STUN服务器 当SIP终端在使用私有IP地址时,可能需要配置stun服务器 公开的免费STUN服务器有: stunserver.org 测试是OK的

Global site tag (gtag.js) - Google Analytics