📄 stun.cxx
字号:
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; }}static void stunSendTest( resip::Socket myFd, StunAddress4& dest, const StunAtrString& username, const StunAtrString& password, int testNum, bool verbose ){ assert( dest.addr != 0 ); assert( dest.port != 0 ); bool changePort=false; bool changeIP=false; bool discard=false; 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: cerr << "Test " << testNum <<" is unkown\n"; assert(0); } StunMessage req; memset(&req, 0, sizeof(StunMessage)); stunBuildReqSimple( &req, username, changePort , changeIP , testNum ); char buf[STUN_MAX_MESSAGE_SIZE]; int len = STUN_MAX_MESSAGE_SIZE; len = stunEncodeMessage( req, buf, len, password,verbose ); if ( verbose ) { clog << "About to send msg of len " << len << " to " << dest << endl; } sendMessage( myFd, buf, len, dest.addr, dest.port, verbose );}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);}bool stunTest( StunAddress4& dest, int testNum, bool verbose, StunAddress4* sAddr, unsigned long timeoutMs ){ assert( dest.addr != 0 ); assert( dest.port != 0 ); int port = stunRandomPort(); UInt32 interfaceIp=0; if (sAddr) { interfaceIp = sAddr->addr; if ( sAddr->port != 0 ) { port = sAddr->port; } } resip::Socket myFd = openPort(port,interfaceIp,verbose); if (myFd == INVALID_SOCKET) { return false; } // make socket non-blocking if (!makeSocketNonBlocking(myFd)) { return false; } StunAtrString username; StunAtrString password; username.sizeValue = 0; password.sizeValue = 0; #ifdef USE_TLS stunGetUserNameAndPassword( dest, username, password );#endif stunSendTest( myFd, dest, username, password, testNum, verbose ); char msg[STUN_MAX_MESSAGE_SIZE]; int msgLen = STUN_MAX_MESSAGE_SIZE; // Wait to receive a packet resip::FdSet myFdSet; myFdSet.setRead(myFd); if (myFdSet.selectMilliSeconds(timeoutMs) < 1) { // no packet received or an error occured return false; } StunAddress4 from; if (!getMessage(myFd, msg, &msgLen, &from.addr, &from.port, verbose)) { closeSocket(myFd); return false; } StunMessage resp; memset(&resp, 0, sizeof(StunMessage)); if ( verbose ) clog << "Got a response" << endl; bool ok = stunParseMessage( msg,msgLen, resp,verbose ); if ( verbose ) { clog << "\t ok=" << ok << endl; clog << "\t id=" << resp.msgHdr.id << endl; clog << "\t mappedAddr=" << resp.mappedAddress.ipv4 << endl; clog << "\t changedAddr=" << resp.changedAddress.ipv4 << endl; clog << endl; } if (sAddr) { sAddr->port = resp.mappedAddress.ipv4.port; sAddr->addr = resp.mappedAddress.ipv4.addr; } closeSocket(myFd); return ok;}NatTypestunNatType( StunAddress4& dest, bool verbose, bool* preservePort, // if set, is return for if NAT preservers ports or not bool* 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 ); if ( hairpin ) { *hairpin = false; } if ( port == 0 ) { port = stunRandomPort(); } UInt32 interfaceIp=0; if (sAddr) { interfaceIp = sAddr->addr; } resip::Socket myFd1 = openPort(port,interfaceIp,verbose); resip::Socket myFd2 = openPort(port+1,interfaceIp,verbose); if ( ( myFd1 == INVALID_SOCKET) || ( myFd2 == INVALID_SOCKET) ) { cerr << "Some problem opening port/interface to send on" << endl; return StunTypeFailure; } assert( myFd1 != INVALID_SOCKET ); assert( myFd2 != INVALID_SOCKET ); bool respTestI=false; bool isNat=true; StunAddress4 testIchangedAddr; StunAddress4 testImappedAddr; bool respTestI2=false; bool mappedIpSame = true; StunAddress4 testI2mappedAddr; StunAddress4 testI2dest=dest; bool respTestII=false; bool respTestIII=false; bool respTestHairpin=false; bool respTestPreservePort=false; memset(&testImappedAddr,0,sizeof(testImappedAddr)); StunAtrString username; StunAtrString password; username.sizeValue = 0; password.sizeValue = 0; #ifdef USE_TLS stunGetUserNameAndPassword( dest, username, password );#endif int count=0; while ( count < 7 ) { struct timeval tv; fd_set fdSet; #ifdef WIN32 unsigned int fdSetSize;#else int fdSetSize;#endif 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=150*1000; // 150 ms if ( count == 0 ) tv.tv_usec=0; int err = select(fdSetSize, &fdSet, NULL, NULL, &tv); int e = getErrno(); if ( err == SOCKET_ERROR ) { // error occured cerr << "Error " << e << " " << strerror(e) << " in select" << endl; 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 { //if (verbose) clog << "-----------------------------------------" << endl; assert( err>0 ); // data is avialbe on some fd for ( int i=0; i<2; i++) { resip::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; getMessage( myFd, msg, &msgLen, &from.addr, &from.port,verbose ); StunMessage resp; memset(&resp, 0, sizeof(StunMessage)); stunParseMessage( msg,msgLen, resp,verbose ); if ( verbose ) { clog << "Received message of type " << resp.msgHdr.msgType << " id=" << (int)(resp.msgHdr.id.octet[0]) << endl; } 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; respTestPreservePort = ( testImappedAddr.port == port ); if ( preservePort ) { *preservePort = respTestPreservePort; } 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: { if ( hairpin ) { *hairpin = true; } respTestHairpin = true; } break; } } } } } } closeSocket(myFd1); closeSocket(myFd2); // see if we can bind to this address //cerr << "try binding to " << testImappedAddr << endl; resip::Socket s = openPort( 0/*use ephemeral*/, testImappedAddr.addr, false ); if ( s != INVALID_SOCKET ) { closeSocket(s); isNat = false; //cerr << "binding worked" << endl; } else { isNat = true; //cerr << "binding failed" << endl; } if (verbose) { clog << "test I = " << respTestI << endl; clog << "test II = " << respTestII << endl; clog << "test III = " << respTestIII << endl; clog << "test I(2) = " << respTestI2 << endl; clog << "is nat = " << isNat <<endl; clog << "mapped IP same = " << mappedIpSame << endl; clog << "hairpin = " << respTestHairpin << endl; clog << "preserver port = " << respTestPreservePort << endl; } #if 0 // implement logic flow chart from draft RFC if ( respTestI ) { if ( isNat ) { if (respTestII) { return StunTypeConeNat; } else { if ( mappedIpSame ) { if ( respTestIII ) { return StunTypeRestrictedNat; } else { return StunTypePortRestrict
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -