📄 stun.cxx
字号:
password->sizeValue = 40; password->value[40]=0; //clog << "password=" << password->value << endl;}UInt64stunGetSystemTimeSecs(){ UInt64 time=0;#if defined(WIN32) SYSTEMTIME t; // CJ TODO - this probably has bug on wrap around every 24 hours GetSystemTime( &t ); time = (t.wHour*60+t.wMinute)*60+t.wSecond; #else struct timeval now; gettimeofday( &now , NULL ); //assert( now ); time = now.tv_sec;#endif return time;}ostream& operator<< ( ostream& strm, const UInt128& r ){ strm << int(r.octet[0]); for ( int i=1; i<16; i++ ) { strm << ':' << int(r.octet[i]); } return strm;}ostream& operator<<( ostream& strm, const StunAddress4& addr){ UInt32 ip = addr.addr; strm << ((int)(ip>>24)&0xFF) << "."; strm << ((int)(ip>>16)&0xFF) << "."; strm << ((int)(ip>> 8)&0xFF) << "."; strm << ((int)(ip>> 0)&0xFF) ; strm << ":" << addr.port; return strm;}ostream&operator<<(ostream& os, const StunMsgHdr& h){ os << "STUN: "; switch (h.msgType) { case BindRequestMsg: os << "BindingRequest"; break; case BindResponseMsg: os << "BindingResponse"; break; case BindErrorResponseMsg: os << "BindingErrorResponse"; break; case TurnAllocateRequest: os << "TurnAllocateRequest"; break; case TurnAllocateResponse: os << "TurnAllocateResponse"; break; case TurnAllocateErrorResponse: os << "TurnAllocateErrorResponse"; break; case TurnSendRequest: os << "TurnSendRequest"; break; case TurnSendResponse: os << "TurnSendResponse"; break; case TurnSendErrorResponse: os << "TurnSendErrorResponse"; break; case TurnDataIndication: os << "TurnDataIndication"; break; case TurnSetActiveDestinationRequest: os << "TurnSetActiveDestinationRequest"; break; case TurnSetActiveDestinationResponse: os << "TurnSetActiveDestinationResponse"; break; case TurnSetActiveDestinationErrorResponse: os << "TurnSetActiveDestinationErrorResponse"; break; } os << ", id "; os << std::hex; for (unsigned int i = 0; i < sizeof(UInt128); i++) { os << static_cast<int>(h.id.octet[i]); } os << std::dec; return os;}// returns true if it scucceededbool stunParseHostName( char* peerName, UInt32& ip, UInt16& portVal, UInt16 defaultPort ){ in_addr sin_addr; char host[512]; strncpy(host,peerName,512); host[512-1]='\0'; char* port = NULL; int portNum = defaultPort; // pull out the port part if present. char* sep = strchr(host,':'); if ( sep == NULL ) { portNum = defaultPort; } else { *sep = '\0'; port = sep + 1; // set port part char* endPtr=NULL; portNum = strtol(port,&endPtr,10); if ( endPtr != NULL ) { if ( *endPtr != '\0' ) { portNum = defaultPort; } } } if ( portNum < 1024 ) return false; if ( portNum >= 0xFFFF ) return false; // figure out the host part struct hostent* h; #ifdef WIN32 assert( strlen(host) >= 1 ); if ( isdigit( host[0] ) ) { // assume it is a ip address unsigned long a = inet_addr(host); //cerr << "a=0x" << hex << a << dec << endl; ip = ntohl( a ); } else { // assume it is a host name h = gethostbyname( host ); if ( h == NULL ) { int err = getErrno(); std::cerr << "error was " << err << std::endl; assert( err != WSANOTINITIALISED ); ip = ntohl( 0x7F000001L ); return false; } else { sin_addr = *(struct in_addr*)h->h_addr; ip = ntohl( sin_addr.s_addr ); } } #else h = gethostbyname( host ); if ( h == NULL ) { int err = getErrno(); std::cerr << "error was " << err << std::endl; ip = ntohl( 0x7F000001L ); return false; } else { sin_addr = *(struct in_addr*)h->h_addr; ip = ntohl( sin_addr.s_addr ); }#endif portVal = portNum; return true;}boolstunParseServerName( char* name, StunAddress4& addr){ assert(name); // TODO - put in DNS SRV stuff. bool ret = stunParseHostName( name, addr.addr, addr.port, 3478); if ( ret != true ) { addr.port=0xFFFF; } return ret;}static voidstunCreateErrorResponse(StunMessage& response, int cl, int number, const char* msg){ response.msgHdr.msgType = BindErrorResponseMsg; response.hasErrorCode = true; response.errorCode.errorClass = cl; response.errorCode.number = number; strcpy(response.errorCode.reason, msg); response.errorCode.sizeReason = strlen(msg);}#if 0static voidstunCreateSharedSecretErrorResponse(StunMessage& response, int cl, int number, const char* msg){ response.msgHdr.msgType = SharedSecretErrorResponseMsg; response.hasErrorCode = true; response.errorCode.errorClass = cl; response.errorCode.number = number; strcpy(response.errorCode.reason, msg);}#endifstatic voidstunCreateSharedSecretResponse(const StunMessage& request, const StunAddress4& source, StunMessage& response){ response.msgHdr.msgType = SharedSecretResponseMsg; response.msgHdr.id = request.msgHdr.id; response.hasUsername = true; stunCreateUserName( source, &response.username); response.hasPassword = true; stunCreatePassword( response.username, &response.password);}// This funtion takes a single message sent to a stun server, parses// and constructs an apropriate repsonse - returns true if message is// validboolstunServerProcessMsg( char* buf, unsigned int bufLen, StunAddress4& from, StunAddress4& secondary, StunAddress4& myAddr, StunAddress4& altAddr, StunMessage* resp, StunAddress4* destination, StunAtrString* hmacPassword, bool* changePort, bool* changeIp, bool verbose){ // set up information for default response memset( resp, 0 , sizeof(*resp) ); *changeIp = false; *changePort = false; StunMessage req; bool ok = stunParseMessage( buf,bufLen, req, verbose); if (!ok) // Complete garbage, drop it on the floor { if (verbose) clog << "Request did not parse" << endl; return false; } if (verbose) clog << "Request parsed ok" << endl; StunAddress4 mapped = req.mappedAddress.ipv4; StunAddress4 respondTo = req.responseAddress.ipv4; UInt32 flags = req.changeRequest.value; switch (req.msgHdr.msgType) { case SharedSecretRequestMsg: if(verbose) clog << "Received SharedSecretRequestMsg on udp. send error 433." << endl; // !cj! - should fix so you know if this came over TLS or UDP stunCreateSharedSecretResponse(req, from, *resp); //stunCreateSharedSecretErrorResponse(*resp, 4, 33, "this request must be over TLS"); return true; case BindRequestMsg: if (!req.hasMessageIntegrity) { if (verbose) clog << "BindRequest does not contain MessageIntegrity" << endl; if (0) // !jf! mustAuthenticate { if(verbose) clog << "Received BindRequest with no MessageIntegrity. Sending 401." << endl; stunCreateErrorResponse(*resp, 4, 1, "Missing MessageIntegrity"); return true; } } else { if (!req.hasUsername) { if (verbose) clog << "No UserName. Send 432." << endl; stunCreateErrorResponse(*resp, 4, 32, "No UserName and contains MessageIntegrity"); return true; } else { if (verbose) clog << "Validating username: " << req.username.value << endl; // !jf! could retrieve associated password from provisioning here if (strcmp(req.username.value, "test") == 0) { if (0) { // !jf! if the credentials are stale stunCreateErrorResponse(*resp, 4, 30, "Stale credentials on BindRequest"); return true; } else { if (verbose) clog << "Validating MessageIntegrity" << endl; // need access to shared secret unsigned char hmac[20];#ifdef USE_SSL unsigned int hmacSize=20; HMAC(EVP_sha1(), "1234", 4, reinterpret_cast<const unsigned char*>(buf), bufLen-20-4, hmac, &hmacSize); assert(hmacSize == 20);#endif if (memcmp(buf, hmac, 20) != 0) { if (verbose) clog << "MessageIntegrity is bad. Sending " << endl; stunCreateErrorResponse(*resp, 4, 3, "Unknown username. Try test with password 1234"); return true; } // need to compute this later after message is filled in resp->hasMessageIntegrity = true; assert(req.hasUsername); resp->hasUsername = true; resp->username = req.username; // copy username in } } else { if (verbose) clog << "Invalid username: " << req.username.value << "Send 430." << endl; } } } // TODO !jf! should check for unknown attributes here and send 420 listing the // unknown attributes. if ( respondTo.port == 0 ) respondTo = from; if ( mapped.port == 0 ) mapped = from; *changeIp = ( flags & ChangeIpFlag )?true:false; *changePort = ( flags & ChangePortFlag )?true:false; if (verbose) { clog << "Request is valid:" << endl; clog << "\t flags=" << flags << endl; clog << "\t changeIp=" << *changeIp << endl; clog << "\t changePort=" << *changePort << endl; clog << "\t from = " << from << endl; clog << "\t respond to = " << respondTo << endl; clog << "\t mapped = " << mapped << endl; } // form the outgoing message resp->msgHdr.msgType = BindResponseMsg; for ( int i=0; i<16; i++ ) { resp->msgHdr.id.octet[i] = req.msgHdr.id.octet[i]; } if ( req.xorOnly == false ) { resp->hasMappedAddress = true; resp->mappedAddress.ipv4.port = mapped.port; resp->mappedAddress.ipv4.addr = mapped.addr; } if (1) // do xorMapped address or not { resp->hasXorMappedAddress = true; UInt16 id16 = req.msgHdr.id.octet[0]<<8 | req.msgHdr.id.octet[1]; UInt32 id32 = req.msgHdr.id.octet[0]<<24 | req.msgHdr.id.octet[1]<<16 | req.msgHdr.id.octet[2]<<8 | req.msgHdr.id.octet[3]; resp->xorMappedAddress.ipv4.port = mapped.port^id16; resp->xorMappedAddress.ipv4.addr = mapped.addr^id32; } resp->hasSourceAddress = true; resp->sourceAddress.ipv4.port = (*changePort) ? altAddr.port : myAddr.port; resp->sourceAddress.ipv4.addr = (*changeIp) ? altAddr.addr : myAddr.addr; resp->hasChangedAddress = true; resp->changedAddress.ipv4.port = altAddr.port; resp->changedAddress.ipv4.addr = altAddr.addr; if ( secondary.port != 0 ) { resp->hasSecondaryAddress = true; resp->secondaryAddress.ipv4.port = secondary.port; resp->secondaryAddress.ipv4.addr = secondary.addr; } if ( req.hasUsername && req.username.sizeValue > 0 ) { // copy username in resp->hasUsername = true; assert( req.username.sizeValue % 4 == 0 ); assert( req.username.sizeValue < STUN_MAX_STRING ); memcpy( resp->username.value, req.username.value, req.username.sizeValue ); resp->username.sizeValue = req.username.sizeValue; } if (1) // add ServerName { resp->hasServerName = true; const char serverName[] = "Vovida.org " STUN_VERSION; // must pad to mult of 4 assert( sizeof(serverName) < STUN_MAX_STRING ); //cerr << "sizeof serverName is " << sizeof(serverName) << endl; assert( sizeof(serverName)%4 == 0 ); memcpy( resp->serverName.value, serverName, sizeof(serverName)); resp->serverName.sizeValue = sizeof(serverName); } if ( req.hasMessageIntegrity & req.hasUsername ) { // this creates the password that will be used in the HMAC when then // messages is sent stunCreatePassword( req.username, hmacPassword ); } if (req.hasUsername && (req.username.sizeValue > 64 ) ) { UInt32 source; assert( sizeof(int) == sizeof(UInt32) ); sscanf(req.username.value, "%x", &source); resp->hasReflectedFrom = true; resp->reflectedFrom.ipv4.port = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -