📄 stun.c
字号:
bool_t changePort, bool_t changeIp, unsigned int id ){ int i; /* assert( msg ); */ memset( msg , 0 , sizeof(*msg) ); msg->msgHdr.msgType = BindRequestMsg; for ( i=0; i<16; i=i+4 ) { /* assert(i+3<16); */ int r = stunRand(); msg->msgHdr.id.octet[i+0]= r>>0; msg->msgHdr.id.octet[i+1]= r>>8; msg->msgHdr.id.octet[i+2]= r>>16; msg->msgHdr.id.octet[i+3]= r>>24; } if ( id != 0 ) { msg->msgHdr.id.octet[0] = id; } msg->hasChangeRequest = TRUE; msg->changeRequest.value =(changeIp?ChangeIpFlag:0) | (changePort?ChangePortFlag:0); if ( username->sizeValue > 0 ) { msg->hasUsername = TRUE; /* msg->username = username; */ memcpy(&msg->username, username, sizeof(StunAtrString)); }}static void stunSendTest( Socket myFd, StunAddress4 *dest, const StunAtrString *username, const StunAtrString *password, int testNum, bool_t verbose ){ /* assert( dest.addr != 0 ); */ /* assert( dest.port != 0 ); */ bool_t changePort=FALSE; bool_t changeIP=FALSE; bool_t discard=FALSE; StunMessage req; char buf[STUN_MAX_MESSAGE_SIZE]; int len = STUN_MAX_MESSAGE_SIZE; switch (testNum) { case 1: case 10: case 11: break; case 2: /* changePort=TRUE; */ changeIP=TRUE; break; case 3: changePort=TRUE; break; case 4: changeIP=TRUE; break; case 5: discard=TRUE; break; default: ortp_error("stun: Test %i is unkown\n", testNum); return ; /* error */ } memset(&req, 0, sizeof(StunMessage)); stunBuildReqSimple( &req, username, changePort , changeIP , testNum ); len = stunEncodeMessage( &req, buf, len, password,verbose ); if ( verbose ) { ortp_message("stun: About to send msg of len %i to %s\n", len, ipaddr(dest) ); } sendMessage( myFd, buf, len, dest->addr, dest->port, verbose ); /* add some delay so the packets don't get sent too quickly */#if defined(_WIN32_WCE) Sleep (10);#elif defined(WIN32)/* !cj! TODO - should fix this up in windows */ { clock_t now = clock(); /* assert( CLOCKS_PER_SEC == 1000 ); */ while ( clock() <= now+10 ) { }; }#else usleep(10*1000);#endif}void stunGetUserNameAndPassword( const StunAddress4 *dest, StunAtrString* username, StunAtrString* password){ /* !cj! This is totally bogus - need to make TLS connection to dest and get a */ /* username and password to use */ stunCreateUserName(dest, username); stunCreatePassword(username, password);}int stunTest( StunAddress4 *dest, int testNum, bool_t verbose, StunAddress4* sAddr , StunAddress4 *sMappedAddr, StunAddress4* sChangedAddr){ /* assert( dest.addr != 0 ); */ /* assert( dest.port != 0 ); */ int port = randomPort(); UInt32 interfaceIp=0; Socket myFd; StunAtrString username; StunAtrString password; char msg[STUN_MAX_MESSAGE_SIZE]; int msgLen = STUN_MAX_MESSAGE_SIZE; StunAddress4 from; StunMessage resp; bool_t ok; if (sAddr) { interfaceIp = sAddr->addr; if ( sAddr->port != 0 ) { port = sAddr->port; } } myFd = openPort(port,interfaceIp,verbose); if ( myFd == INVALID_SOCKET) return -1; username.sizeValue = 0; password.sizeValue = 0; #ifdef USE_TLS stunGetUserNameAndPassword( dest, &username, &password );#endif stunSendTest( myFd, dest, &username, &password, testNum, verbose ); ok = getMessage( myFd, msg, &msgLen, &from.addr, &from.port,verbose ); closesocket(myFd); if (!ok) return -1; memset(&resp, 0, sizeof(StunMessage)); if ( verbose ) ortp_message("stun: Got a response"); ok = stunParseMessage( msg,msgLen, &resp,verbose ); if ( verbose ) { ortp_message("stun: \t ok=%i\n", ok );#if defined(WIN32) || defined(_WIN32_WCE) ortp_message("stun: \t id=%u\n", *(unsigned int*)&resp.msgHdr.id );#endif ortp_message("stun: \t mappedAddr=%i\n", resp.mappedAddress.ipv4.addr ); ortp_message("stun: \t changedAddr=%i\n", resp.changedAddress.ipv4.addr ); } if (sAddr) { sAddr->port = port; } if (sMappedAddr) { sMappedAddr->port = resp.mappedAddress.ipv4.port; sMappedAddr->addr = resp.mappedAddress.ipv4.addr; } if (sChangedAddr) { sChangedAddr->port = resp.changedAddress.ipv4.port; sChangedAddr->addr = resp.changedAddress.ipv4.addr; } if (ok) return 0; else return -1;}NatTypestunNatType( StunAddress4 *dest, bool_t verbose, bool_t* preservePort, /* if set, is return for if NAT preservers ports or not */ bool_t* hairpin, /* if set, is the return for if NAT will hairpin packets */ int port, /* port to use for the test, 0 to choose random port */ StunAddress4* sAddr /* NIC to use */ ){ /* assert( dest.addr != 0 ); */ /* assert( dest.port != 0 ); */ UInt32 interfaceIp=0; Socket myFd1; Socket myFd2; bool_t respTestI=FALSE; bool_t isNat=TRUE; StunAddress4 testIchangedAddr; StunAddress4 testImappedAddr; bool_t respTestI2=FALSE; bool_t mappedIpSame = TRUE; StunAddress4 testI2mappedAddr; /* StunAddress4 testI2dest=dest; */ StunAddress4 testI2dest; bool_t respTestII=FALSE; bool_t respTestIII=FALSE; bool_t respTestHairpin=FALSE; StunAtrString username; StunAtrString password; int count=0; UInt64 second_started; UInt64 second_elapsed; Socket s; if ( hairpin ) { *hairpin = FALSE; } if ( port == 0 ) { port = randomPort(); } if (sAddr) { interfaceIp = sAddr->addr; } myFd1 = openPort(port,interfaceIp,verbose); myFd2 = openPort(port+1,interfaceIp,verbose); if ( ( myFd1 == INVALID_SOCKET) || ( myFd2 == INVALID_SOCKET) ) { ortp_error("stun: Some problem opening port/interface to send on\n"); return StunTypeFailure; } /* assert( myFd1 != INVALID_SOCKET ); */ /* assert( myFd2 != INVALID_SOCKET ); */ memcpy(&testI2dest, dest, sizeof(StunAddress4)); memset(&testImappedAddr,0,sizeof(testImappedAddr)); username.sizeValue = 0; password.sizeValue = 0; #ifdef USE_TLS stunGetUserNameAndPassword( dest, username, password );#endif /* stunSendTest( myFd1, dest, username, password, 1, verbose ); */ second_started = stunGetSystemTimeSecs(); second_elapsed = 1; while ( count < 7 && second_elapsed < 5) { struct timeval tv; fd_set fdSet; int err; int e;#if defined(WIN32) || defined(_WIN32_WCE) unsigned int fdSetSize;#else int fdSetSize;#endif second_elapsed = stunGetSystemTimeSecs() - second_started ; FD_ZERO(&fdSet); fdSetSize=0; FD_SET(myFd1,&fdSet); fdSetSize = (myFd1+1>fdSetSize) ? myFd1+1 : fdSetSize; FD_SET(myFd2,&fdSet); fdSetSize = (myFd2+1>fdSetSize) ? myFd2+1 : fdSetSize; tv.tv_sec=0; tv.tv_usec=500*1000; /* 150 ms */ if ( count == 0 ) tv.tv_usec=0; err = select(fdSetSize, &fdSet, NULL, NULL, &tv); e = getErrno(); if ( err == SOCKET_ERROR ) { /* error occured */#if !defined(_WIN32_WCE) ortp_error("stun: Error %i %s in select\n", e, strerror(e));#else ortp_error("stun: Error %i in select\n", e);#endif closesocket(myFd1); /* AMD */ closesocket(myFd2); /* AMD */ return StunTypeFailure; } else if ( err == 0 ) { /* timeout occured */ count++; if ( !respTestI ) { stunSendTest( myFd1, dest, &username, &password, 1 ,verbose ); } if ( (!respTestI2) && respTestI ) { /* check the address to send to if valid */ if ( ( testI2dest.addr != 0 ) && ( testI2dest.port != 0 ) ) { stunSendTest( myFd1, &testI2dest, &username, &password, 10 ,verbose); } } if ( !respTestII ) { stunSendTest( myFd2, dest, &username, &password, 2 ,verbose ); } if ( !respTestIII ) { stunSendTest( myFd2, dest, &username, &password, 3 ,verbose ); } if ( respTestI && (!respTestHairpin) ) { if ( ( testImappedAddr.addr != 0 ) && ( testImappedAddr.port != 0 ) ) { stunSendTest( myFd1, &testImappedAddr, &username, &password, 11 ,verbose ); } } } else { int i; /* if (verbose) ortp_message("stun: -----------------------------------------"); */ /* assert( err>0 ); */ /* data is avialbe on some fd */ for ( i=0; i<2; i++) { Socket myFd; if ( i==0 ) { myFd=myFd1; } else { myFd=myFd2; } if ( myFd!=INVALID_SOCKET ) { if ( FD_ISSET(myFd,&fdSet) ) { char msg[STUN_MAX_MESSAGE_SIZE]; int msgLen = sizeof(msg); StunAddress4 from; StunMessage resp; getMessage( myFd, msg, &msgLen, &from.addr, &from.port,verbose ); memset(&resp, 0, sizeof(StunMessage)); stunParseMessage( msg,msgLen, &resp,verbose ); if ( verbose ) { ortp_message("stun: Received message of type %i id=%i\n", resp.msgHdr.msgType, (int)(resp.msgHdr.id.octet[0]) ); } switch( resp.msgHdr.id.octet[0] ) { case 1: { if ( !respTestI ) { testIchangedAddr.addr = resp.changedAddress.ipv4.addr; testIchangedAddr.port = resp.changedAddress.ipv4.port; testImappedAddr.addr = resp.mappedAddress.ipv4.addr; testImappedAddr.port = resp.mappedAddress.ipv4.port; if ( preservePort ) { *preservePort = ( testImappedAddr.port == port ); } testI2dest.addr = resp.changedAddress.ipv4.addr; if (sAddr) { sAddr->port = testImappedAddr.port; sAddr->addr = testImappedAddr.addr; } count = 0; } respTestI=TRUE; } break; case 2: { respTestII=TRUE; } break; case 3: { respTestIII=TRUE; } break; case 10: { if ( !respTestI2 ) { testI2mappedAddr.addr = resp.mappedAddress.ipv4.addr; testI2mappedAddr.port = resp.mappedAddress.ipv4.port; mappedIpSame = FALSE; if ( (testI2mappedAddr.addr == testImappedAddr.addr ) && (testI2mappedAddr.port == testImappedAddr.port )) { mappedIpSame = TRUE; } } respTestI2=TRUE; } break; case 11:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -