/*NAT stun,DGRAM manner*/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <arpa/inet.h> #include <sys/time.h> #include <sys/resource.h> #include <errno.h> #include <unistd.h> #include <net/if.h> #include <fcntl.h> #include <pthread.h> #include <sys/ioctl.h> #define STUN_UDP_PORT 9002 #define STUN_TEST_SERVER_PORT 9001 char natTestUrl[64]=""; typedef struct { unsigned short msgType; unsigned int msgLength; }stunMsgHdr; typedef struct timeval TIMEVAL; typedef struct{ stunMsgHdr hdr; char oui[24]; char sn[64]; char stbUser[64]; unsigned int srcAddr; unsigned short srcPort; unsigned int mappedAddr; unsigned char mappedPort; }stunMsg;//stun message static void getLocalAddr(char *localAddr){ int inet_sock; struct ifreq ifr; unsigned char addr[6]; inet_sock = socket(AF_INET, SOCK_DGRAM, 0); if(inet_sock<0) printf("create sock error/n"); strcpy(ifr.ifr_name, "eth0"); if(ioctl(inet_sock,SIOCGIFADDR,&ifr)<0){ printf("can/'t get local Ip,reason %s/n",strerror(errno)); close(inet_sock); exit; } printf("----1111111/n"); bzero(localAddr,0x00); strcpy(localAddr,inet_ntoa(((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr)); printf("the localAddr is:%s in func1/n", localAddr); } static unsigned int calculateTimeMs(TIMEVAL tv1, TIMEVAL tv2) { if(tv2.tv_sec < tv1.tv_sec) { printf("tv2 < tv1 error/n"); return 0; } if(tv2.tv_usec >= tv1.tv_usec) { return ((tv2.tv_sec - tv1.tv_sec)*1000 + (tv2.tv_usec - tv1.tv_usec)/1000); } else { if(tv2.tv_sec == tv1.tv_sec) { return 0; } return((tv2.tv_sec - tv1.tv_sec)*1000 - (tv1.tv_usec - tv2.tv_usec)/1000); } } int NATTest(const char *oui , const char *sn, const char *serviceUser, const char *serverAddr, const char *localAddr) { int _sock; struct sockaddr_in _addr; struct sockaddr_in _toAddr; struct sockaddr_in _servAddr; fd_set _reader; char buf[2048] = ""; char recvBuf[2048] = ""; stunMsg recvMsg; /* * init the socket */ _sock = socket(AF_INET, SOCK_DGRAM, 0); if (_sock < 0) { #ifdef DEBUG CT_LOG_ERR(NULL, LOG_TYPE_OTHER, "create UDP socket error."); #endif return 0; } else { #ifdef DEBUG CT_LOG_INFO(NULL, LOG_TYPE_OTHER, "Created udp socket is: %d", sock); #endif } int _nREUSEADDR = 1; setsockopt(_sock,SOL_SOCKET,SO_REUSEADDR,(const char*)&_nREUSEADDR,sizeof(int)); memset (&_addr, 0, sizeof (struct sockaddr_in)); _addr.sin_family = AF_INET; _addr.sin_addr.s_addr = inet_addr(localAddr); _addr.sin_port = htons(STUN_UDP_PORT); /* * Bind socket */ int ret = bind (_sock, (struct sockaddr *) &_addr, sizeof (struct sockaddr_in)); if(ret < 0 ) { #ifdef DEBUG CT_LOG_ERR(NULL, LOG_TYPE_OTHER, "Bind socket error."); #endif close(_sock); return 0; } /* * init the message */ stunMsg message; memset(&message, 0x00, sizeof(stunMsg)); //strcpy(message.srcAddr, localAddr); message.srcAddr = inet_addr(localAddr); message.srcPort = STUN_UDP_PORT; message.hdr.msgLength = sizeof(stunMsg); message.hdr.msgType = 0x1234;//just test strcpy(message.oui, oui); strcpy(message.sn, sn); strcpy(message.stbUser, serviceUser); /* * Then send test packet to stun server */ int _toLen = sizeof(_toAddr); memset(&_toAddr,0x00,_toLen); _toAddr.sin_family = AF_INET; _toAddr.sin_port = htons(STUN_TEST_SERVER_PORT); _toAddr.sin_addr.s_addr = inet_addr(serverAddr); memcpy(buf, &message, sizeof(stunMsg)); unsigned short * _ip = (unsigned short *)&_toAddr.sin_addr.s_addr; printf("server: %s/n", serverAddr); printf("direct address: %d.%d.%d.%d : %d/n", _ip[0], _ip[1], _ip[2], _ip[3], ntohs(_toAddr.sin_port)); ret = sendto(_sock, buf, sizeof(stunMsg), 0,(struct sockaddr *)&_toAddr, _toLen); if(ret == -1) { #ifdef DEBUG CT_LOG_ERR(NULL,LOG_TYPE_OTHER,"Send bind request error."); #endif printf("send request error/n"); close(_sock); return 0; } TIMEVAL nat_test_end_tv, tv, now; gettimeofday(&nat_test_end_tv, NULL); nat_test_end_tv.tv_sec += 5; unsigned int time_wait; nat_test_select: //TIMEVAL tv = { 5 , 0 }; gettimeofday(&now, NULL); time_wait = calculateTimeMs(now, nat_test_end_tv); if(time_wait == 0) { #ifdef DEBUG CT_LOG_INFO(NULL,LOG_TYPE_OTHER,"NAT test time out ."); #endif close(_sock); //out of time return 0; } tv.tv_sec = time_wait/1000; tv.tv_usec = (time_wait%1000) * 1000; FD_ZERO(&_reader); FD_SET(_sock, &_reader); ret = select(_sock+1, &_reader, NULL, NULL, &tv ); if(ret == 0) { #ifdef DEBUG CT_LOG_INFO(NULL, LOG_TYPE_OTHER, "NAT test time out ."); #endif printf("nat test time out"); close(_sock); //out of time return 0; } if(ret < 0) { if(errno == EINTR) { goto nat_test_select; } else { #ifdef DEBUG CT_LOG_WARN(NULL, LOG_TYPE_OTHER, "[ctThreadMgr]: select() error: [%s]", strerror(errno)); #endif printf("select error/n"); close(_sock); return 0; }//close(sock); } socklen_t len = sizeof(_servAddr); ret = recvfrom(_sock, recvBuf, 2048, 0, (struct sockaddr *)&_servAddr, &len); if(ret != sizeof(stunMsg)) { #ifdef DEBUG CT_LOG_ERR(NULL, LOG_TYPE_OTHER, "recv data error."); #endif close(_sock); return 0; } else { memcpy(&recvMsg, recvBuf, sizeof(stunMsg)); if(recvMsg.mappedAddr == inet_addr(localAddr)) { #ifdef DEBUG CT_LOG_INFO(NULL, LOG_TYPE_OTHER, i "The client do not use NAT ."); #endif printf("not usd nat/n"); close(_sock); return -1;//return -1 only when we can confirm the STB do not use NAT } else { #ifdef DEBUG CT_LOG_INFO(NULL, LOG_TYPE_OTHER, "The client use NAT ."); #endif printf("use nat/n"); unsigned short *ipAddr = (unsigned short *)&recvMsg.mappedAddr; //pthread_mutex_lock(&natTestUrlMutex); memset(natTestUrl, 0x00, 64); sprintf(natTestUrl, "%d.%d.%d.%d:%d", ipAddr[0],ipAddr[1], ipAddr[2], ipAddr[3],ntohs(recvMsg.mappedPort)); //CT_LOG_INFO(NULL, LOG_TYPE_STUNCLIENT, "Record natTestUrl: %s", natTestUrl); printf("record nattestUrl is%s",natTestUrl); //pthread_mutex_unlock(&natTestUrlMutex); close(_sock); return 1;//return 1 only when we can confirm the STB use NAT } } close(_sock); return 0; } int main(){ const char *oui="98e7454"; const char *sn="a0112cc5"; const char *serviceUser="neeec196"; const char *serverAddr="58.223.77.41"; char localAddr[40]=""; getLocalAddr(localAddr); int ret=NATTest(oui,sn,serviceUser,serverAddr,localAddr); if(ret<0) perror("nat test error"); }