QString StunClient::getStunAddress(QByteArray resp, uint16_t attr_type) { stun_buffer buf; u08bits addr_buff[STUN_BUFFER_SIZE] = {0}; buf.len = resp.length(); memcpy(buf.buf, resp.data(), resp.length()); uint16_t t_attr_type; const u08bits *attr_value; int attr_len; ioa_addr stun_addr; stun_attr_ref raw_attr = stun_attr_get_first_str(buf.buf, buf.len); for ( ; raw_attr ; raw_attr = stun_attr_get_next_str(buf.buf, buf.len, raw_attr)) { t_attr_type = stun_attr_get_type(raw_attr); attr_value = stun_attr_get_value(raw_attr); attr_len = stun_attr_get_len(raw_attr); if (t_attr_type == attr_type) { stun_attr_get_addr_str(buf.buf, buf.len, raw_attr, &stun_addr, NULL); addr_to_string(&stun_addr, (u08bits*)addr_buff); break; } } return QString((char*)addr_buff); }
int read_mobility_ticket(app_ur_conn_info *clnet_info, stun_buffer *message) { int ret = 0; if(clnet_info && message) { stun_attr_ref s_mobile_id_sar = stun_attr_get_first_by_type(message, STUN_ATTRIBUTE_MOBILITY_TICKET); if(s_mobile_id_sar) { int smid_len = stun_attr_get_len(s_mobile_id_sar); if(smid_len>0 && (((size_t)smid_len)<sizeof(clnet_info->s_mobile_id))) { const u08bits* smid_val = stun_attr_get_value(s_mobile_id_sar); if(smid_val) { ns_bcopy(smid_val, clnet_info->s_mobile_id, (size_t)smid_len); clnet_info->s_mobile_id[smid_len] = 0; if (clnet_verbose) TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: smid=%s\n", __FUNCTION__, clnet_info->s_mobile_id); } } else { TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: ERROR: smid_len=%d\n", __FUNCTION__, smid_len); ret = -1; } } } return ret; }
/* * Password retrieval */ int get_user_key(int in_oauth, int *out_oauth, int *max_session_time, u08bits *usname, u08bits *realm, hmackey_t key, ioa_network_buffer_handle nbh) { int ret = -1; if(max_session_time) *max_session_time = 0; if(in_oauth && out_oauth && usname && usname[0]) { stun_attr_ref sar = stun_attr_get_first_by_type_str(ioa_network_buffer_data(nbh), ioa_network_buffer_get_size(nbh), STUN_ATTRIBUTE_OAUTH_ACCESS_TOKEN); if(sar) { int len = stun_attr_get_len(sar); const u08bits *value = stun_attr_get_value(sar); *out_oauth = 1; if(len>0 && value) { const turn_dbdriver_t * dbd = get_dbdriver(); if (dbd && dbd->get_oauth_key) { oauth_key_data_raw rawKey; ns_bzero(&rawKey,sizeof(rawKey)); int gres = (*(dbd->get_oauth_key))(usname,&rawKey); if(gres<0) return ret; if(!rawKey.kid[0]) return ret; if(rawKey.lifetime) { if(!turn_time_before(turn_time(),(turn_time_t)(rawKey.timestamp + rawKey.lifetime+OAUTH_TIME_DELTA))) { return ret; } } oauth_key_data okd; ns_bzero(&okd,sizeof(okd)); convert_oauth_key_data_raw(&rawKey, &okd); char err_msg[1025] = "\0"; size_t err_msg_size = sizeof(err_msg) - 1; oauth_key okey; ns_bzero(&okey,sizeof(okey)); if (convert_oauth_key_data(&okd, &okey, err_msg, err_msg_size) < 0) { TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s\n", err_msg); return -1; } oauth_token dot; ns_bzero((&dot),sizeof(dot)); encoded_oauth_token etoken; ns_bzero(&etoken,sizeof(etoken)); if((size_t)len > sizeof(etoken.token)) { TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Encoded oAuth token is too large\n"); return -1; } ns_bcopy(value,etoken.token,(size_t)len); etoken.size = (size_t)len; const char* server_name = (char*)turn_params.oauth_server_name; if(!(server_name && server_name[0])) { server_name = (char*)realm; if(!(server_name && server_name[0])) { TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot determine oAuth server name"); return -1; } } if (decode_oauth_token((const u08bits *) server_name, &etoken,&okey, &dot) < 0) { TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot decode oauth token\n"); return -1; } switch(dot.enc_block.key_length) { case SHA1SIZEBYTES: if(turn_params.shatype != SHATYPE_SHA1) { TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong size of the MAC key in oAuth token(1): %d\n",(int)dot.enc_block.key_length); return -1; } break; case SHA256SIZEBYTES: if(turn_params.shatype != SHATYPE_SHA256) { TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong size of the MAC key in oAuth token(2): %d\n",(int)dot.enc_block.key_length); return -1; } break; case SHA384SIZEBYTES: if(turn_params.shatype != SHATYPE_SHA384) { TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong size of the MAC key in oAuth token(3): %d\n",(int)dot.enc_block.key_length); return -1; } break; case SHA512SIZEBYTES: if(turn_params.shatype != SHATYPE_SHA512) { TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong size of the MAC key in oAuth token(3): %d\n",(int)dot.enc_block.key_length); return -1; } break; default: TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong size of the MAC key in oAuth token(3): %d\n",(int)dot.enc_block.key_length); return -1; }; password_t pwdtmp; if(stun_check_message_integrity_by_key_str(TURN_CREDENTIALS_LONG_TERM, ioa_network_buffer_data(nbh), ioa_network_buffer_get_size(nbh), dot.enc_block.mac_key, pwdtmp, turn_params.shatype,NULL)>0) { turn_time_t lifetime = (turn_time_t)(dot.enc_block.lifetime); if(lifetime) { turn_time_t ts = (turn_time_t)(dot.enc_block.timestamp >> 16); turn_time_t to = ts + lifetime + OAUTH_TIME_DELTA; turn_time_t ct = turn_time(); if(!turn_time_before(ct,to)) { TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "oAuth token is too old\n"); return -1; } if(max_session_time) { *max_session_time = to - ct; } } ns_bcopy(dot.enc_block.mac_key,key,dot.enc_block.key_length); ret = 0; } } }
void StunClient::debugStunResponse(QByteArray resp) { u08bits rbuf[STUN_BUFFER_SIZE]; size_t rlen = 0; stun_buffer buf; u08bits addr_buff[STUN_BUFFER_SIZE] = {0}; rlen = resp.length(); memcpy(rbuf, resp.data(), resp.length()); buf.len = resp.length(); memcpy(buf.buf, resp.data(), resp.length()); if (!stun_is_command_message(&buf)) { qDebug()<<resp.length()<<("The response is not a STUN message\n"); return; } if (!stun_is_response(&buf)) { qDebug()<<resp.length()<<("The response is not a reponse message\n"); // return; } u16bits stun_method; u16bits stun_msg_type; stun_method = stun_get_method_str(buf.buf, buf.len); stun_msg_type = stun_get_msg_type_str(buf.buf, buf.len); qDebug()<<"method:"<<stun_method<<getMethodName(stun_method)<<",msg type:"<<stun_msg_type; int attr_type; const u08bits *attr_value; int attr_len; char relayed_addr_str[32] = {0}; char mapped_addr_str[32] = {0}; char addr_str[32] = {0}; ioa_addr relayed_addr; ioa_addr mapped_addr; ioa_addr stun_addr; uint32_t lifetime = 0; uint32_t bandwidth = 0; stun_attr_ref raw_attr = stun_attr_get_first_str(buf.buf, buf.len); for ( ; raw_attr ; raw_attr = stun_attr_get_next_str(buf.buf, buf.len, raw_attr)) { attr_type = stun_attr_get_type(raw_attr); attr_value = stun_attr_get_value(raw_attr); attr_len = stun_attr_get_len(raw_attr); switch (attr_type) { case STUN_ATTRIBUTE_SOFTWARE: qDebug()<<"attr software:"<<QByteArray((char*)attr_value, attr_len); break; case STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS: stun_attr_get_addr_str(buf.buf, buf.len, raw_attr, &mapped_addr, NULL); addr_to_string(&mapped_addr, (u08bits*)mapped_addr_str); qDebug()<<"mapped addr:"<<mapped_addr_str; break; case STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS: stun_attr_get_addr_str(buf.buf, buf.len, raw_attr, &relayed_addr, NULL); addr_to_string(&relayed_addr, (u08bits*)relayed_addr_str); qDebug()<<"relayed addr:"<<relayed_addr_str; break; case STUN_ATTRIBUTE_MESSAGE_INTEGRITY: qDebug()<<"message integrity:"<<attr_len<<QByteArray((char*)attr_value, attr_len).toHex(); break; case STUN_ATTRIBUTE_LIFETIME: memcpy(&lifetime, attr_value, attr_len); lifetime = nswap32(lifetime); qDebug()<<"lifetime:"<<lifetime; break; case STUN_ATTRIBUTE_BANDWIDTH: memcpy(&bandwidth, attr_value, attr_len); bandwidth = nswap32(bandwidth); qDebug()<<"bandwidth:"<<bandwidth; break; case STUN_ATTRIBUTE_XOR_PEER_ADDRESS: stun_attr_get_addr_str(buf.buf, buf.len, raw_attr, &stun_addr, NULL); addr_to_string(&stun_addr, (u08bits*)addr_str); qDebug()<<"xor peer addr:"<<addr_str; break; case STUN_ATTRIBUTE_DATA: qDebug()<<"attr data len:"<<attr_len<<QString(QByteArray((char*)attr_value + 4, attr_len - 4)).left(50)<<"..."; break; default: qDebug()<<"unkown attr:"<<attr_type<<attr_len; break; } } }
void StunClient::processResponse(QByteArray resp, QString peer_addr) { u08bits rbuf[STUN_BUFFER_SIZE]; size_t rlen = 0; stun_buffer buf; QString mapped_addr; u08bits addr_buff[STUN_BUFFER_SIZE] = {0}; rlen = resp.length(); memcpy(rbuf, resp.data(), resp.length()); buf.len = resp.length(); memcpy(buf.buf, resp.data(), resp.length()); if (!stun_is_command_message(&buf)) { qDebug()<<resp.length()<<("The response is not a STUN message")<<peer_addr; // should be a relayed raw UDP packet to peerA emit packetReceived(resp, peer_addr); return; } u16bits stun_method; u16bits stun_msg_type; stun_method = stun_get_method_str(buf.buf, buf.len); stun_msg_type = stun_get_msg_type_str(buf.buf, buf.len); qDebug()<<"method:"<<stun_method<<getMethodName(stun_method)<<",msg type:"<<stun_msg_type; if (stun_method == STUN_METHOD_BINDING) { } else { this->debugStunResponse(resp); } // channel data if (stun_is_indication(&buf)) { u16bits chan_no; size_t blen = 0; qDebug()<<"indication data:"<<buf.len; stun_attr_ref t_attr = stun_attr_get_first_by_type(&buf, STUN_ATTRIBUTE_DATA); const u08bits *t_value = stun_attr_get_value(t_attr); blen = stun_attr_get_len(t_attr); QString xor_peer_addr = getStunAddress(resp, STUN_ATTRIBUTE_XOR_PEER_ADDRESS); qDebug()<<"is chan msg:"<<stun_is_channel_message_str(t_value, &blen, &chan_no, 0); qDebug()<<"chan no:"<<chan_no<<blen<<xor_peer_addr; emit this->packetReceived(QByteArray((char*)t_value + 4, blen - 4), xor_peer_addr); return; } if (!stun_is_response(&buf)) { qDebug()<<resp.length()<<("The response is not a reponse message\n"); return; } if (!stun_is_success_response(&buf)) { int err_code = 0; u08bits err_msg[1025] = "\0"; size_t err_msg_size = sizeof(err_msg); if (stun_is_error_response(&buf, &err_code, err_msg, err_msg_size)) { printf("The response is an error %d (%s)\n", err_code, (char*) err_msg); } else { printf("The response is an unrecognized error\n"); } // test unauth u08bits realm[128] = {0}; u08bits nonce[256] = {0}; if (stun_is_challenge_response_str(buf.buf, buf.len, &err_code, err_msg, err_msg_size, realm, nonce)) { qDebug()<<err_code; qDebug()<<err_code<<(char*)err_msg<<(char*)realm<<(char*)nonce; m_realm = QByteArray((char*)realm); m_nonce = QByteArray((char*)nonce); if (stun_method == STUN_METHOD_ALLOCATE) { this->allocate((char*)realm, (char*)nonce); } if (stun_method == STUN_METHOD_CHANNEL_BIND) { QThread::msleep(100); this->channelBind(m_peer_addr); } } if (err_code == 437) { assert(err_code != 437); // allocate mismatch } if (err_code == 438) { assert(err_code != 438); // stale nonce } if (err_code == 486) { assert(err_code != 486); // allocate quota reached } return; } if (stun_is_binding_response(&buf)) { ioa_addr reflexive_addr; addr_set_any(&reflexive_addr); if (stun_attr_get_first_addr(&buf, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, &reflexive_addr, NULL) >= 0) { stun_attr_ref sar = stun_attr_get_first_by_type_str(buf.buf, buf.len, STUN_ATTRIBUTE_OTHER_ADDRESS); if (sar) { // *rfc5780 = 1; printf("\n========================================\n"); // printf("RFC 5780 response %d\n",++counter); ioa_addr other_addr; stun_attr_get_addr_str((u08bits *) buf.buf, (size_t) buf.len, sar, &other_addr, NULL); sar = stun_attr_get_first_by_type_str(buf.buf, buf.len, STUN_ATTRIBUTE_RESPONSE_ORIGIN); if (sar) { ioa_addr response_origin; stun_attr_get_addr_str((u08bits *) buf.buf, (size_t) buf.len, sar, &response_origin, NULL); addr_debug_print(1, &response_origin, "Response origin: "); } addr_debug_print(1, &other_addr, "Other addr: "); } addr_debug_print(1, &reflexive_addr, "UDP reflexive addr"); addr_to_string(&reflexive_addr, addr_buff); } else { printf("Cannot read the response\n"); } // emit got addr if (strlen((char*)addr_buff) > 0) { mapped_addr = QString((char*)addr_buff); emit this->mappedAddressRecieved(mapped_addr); } return; } // end bind resp if (stun_method == STUN_METHOD_ALLOCATE) { m_relayed_addr = this->getStunAddress(resp, STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS); this->saveAllocatePuples(m_realm, m_nonce); emit this->allocateDone(m_relayed_addr); if (!m_channel_refresh_timer) { m_channel_refresh_timer = new QTimer(); QObject::connect(m_channel_refresh_timer, &QTimer::timeout, this, &StunClient::onRefreshTimeout); } if (!m_channel_refresh_timer->isActive()) { m_channel_refresh_timer->start(m_channel_refresh_timeout); } } if (stun_method == STUN_METHOD_CREATE_PERMISSION) { if (!m_permission_keepalive_timer) { emit this->createPermissionDone(); } if (!m_permission_keepalive_timer) { m_permission_keepalive_timer = new QTimer(); QObject::connect(m_permission_keepalive_timer, &QTimer::timeout, this, &StunClient::onPermKATimeout); } if (!m_permission_keepalive_timer->isActive()) { m_permission_keepalive_timer->start(m_permission_keepalive_timeout); } } if (stun_method == STUN_METHOD_CHANNEL_BIND) { emit this->channelBindDone(m_relayed_addr); } if (stun_method == STUN_METHOD_REFRESH) { qDebug()<<"refresh responsed."; } }
/* * Password retrieval */ int get_user_key(int in_oauth, int *out_oauth, int *max_session_time, u08bits *usname, u08bits *realm, hmackey_t key, ioa_network_buffer_handle nbh) { /* Decode certificate */ struct certificate cert; memset(&cert, 0, sizeof cert); unsigned char const *secret_key = (unsigned char *)turn_params.secret_key; unsigned char const *iv = (unsigned char *)turn_params.secret_iv; stun_attr_ref sar = stun_attr_get_first_by_type_str(ioa_network_buffer_data(nbh), ioa_network_buffer_get_size(nbh), STUN_ATTRIBUTE_SOFTWARE); if (sar) { int token_len = stun_attr_get_len(sar); const u08bits* token_ptr = stun_attr_get_value(sar); u08bits token[128]; memcpy(token, token_ptr, token_len); token[token_len]=0; int err = stun_check_message_certificate(token, token_len, &cert, secret_key, iv); if(token_len && err == 0) { const char* password = cert.call_id; size_t sz = get_hmackey_size(SHATYPE_DEFAULT) * 2; char skey[sizeof(hmackey_t) * 2 + 1]; password2hmac(password, usname, realm, skey); if(convert_string_key_to_binary(skey, key, sz / 2) < 0) { TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong key: %s, user %s\n", skey, usname); } char buff[20]; struct tm * timeinfo; timeinfo = localtime (&cert.deadline); strftime(buff, sizeof(buff), "%Y %b %d %H:%M", timeinfo); time_t now; now = time(NULL); /* if(now - cert.deadline < -60 || // server's time's wrong? more tann 60 sec time diff now - cert.deadline > 60*60*24 ) // too much diff, something wrong { TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Token expired: user: %s token: %s time: %s time_diff: %d sec\n", usname, token, buff, now - cert.deadline); return -1; } */ TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Token decrypted: user:%s seq:%s time:%s call:%s \n", usname, cert.seq, buff, cert.call_id); return 0; } else { TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Incorrect token: user %s token: %s Error: %d\n", usname, token, err); return -1; } } else TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "Tokent not found: user %s\n", usname); int ret = -1; if(max_session_time) *max_session_time = 0; if(in_oauth && out_oauth && usname && usname[0]) { stun_attr_ref sar = stun_attr_get_first_by_type_str(ioa_network_buffer_data(nbh), ioa_network_buffer_get_size(nbh), STUN_ATTRIBUTE_OAUTH_ACCESS_TOKEN); if(sar) { int len = stun_attr_get_len(sar); const u08bits *value = stun_attr_get_value(sar); *out_oauth = 1; if(len>0 && value) { const turn_dbdriver_t * dbd = get_dbdriver(); if (dbd && dbd->get_oauth_key) { oauth_key_data_raw rawKey; ns_bzero(&rawKey,sizeof(rawKey)); int gres = (*(dbd->get_oauth_key))(usname,&rawKey); if(gres<0) return ret; if(!rawKey.kid[0]) return ret; if(rawKey.lifetime) { if(!turn_time_before(turn_time(),(turn_time_t)(rawKey.timestamp + rawKey.lifetime+OAUTH_TIME_DELTA))) { return ret; } } oauth_key_data okd; ns_bzero(&okd,sizeof(okd)); convert_oauth_key_data_raw(&rawKey, &okd); char err_msg[1025] = "\0"; size_t err_msg_size = sizeof(err_msg) - 1; oauth_key okey; ns_bzero(&okey,sizeof(okey)); if (convert_oauth_key_data(&okd, &okey, err_msg, err_msg_size) < 0) { TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s\n", err_msg); return -1; } oauth_token dot; ns_bzero((&dot),sizeof(dot)); encoded_oauth_token etoken; ns_bzero(&etoken,sizeof(etoken)); if((size_t)len > sizeof(etoken.token)) { TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Encoded oAuth token is too large\n"); return -1; } ns_bcopy(value,etoken.token,(size_t)len); etoken.size = (size_t)len; const char* server_name = (char*)turn_params.oauth_server_name; if(!(server_name && server_name[0])) { server_name = (char*)realm; if(!(server_name && server_name[0])) { TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot determine oAuth server name"); return -1; } } if (decode_oauth_token((const u08bits *) server_name, &etoken,&okey, &dot) < 0) { TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot decode oauth token\n"); return -1; } switch(dot.enc_block.key_length) { case SHA1SIZEBYTES: break; case SHA256SIZEBYTES: case SHA384SIZEBYTES: case SHA512SIZEBYTES: default: TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong size of the MAC key in oAuth token(3): %d\n",(int)dot.enc_block.key_length); return -1; }; password_t pwdtmp; if(stun_check_message_integrity_by_key_str(TURN_CREDENTIALS_LONG_TERM, ioa_network_buffer_data(nbh), ioa_network_buffer_get_size(nbh), dot.enc_block.mac_key, pwdtmp, SHATYPE_DEFAULT)>0) { turn_time_t lifetime = (turn_time_t)(dot.enc_block.lifetime); if(lifetime) { turn_time_t ts = (turn_time_t)(dot.enc_block.timestamp >> 16); turn_time_t to = ts + lifetime + OAUTH_TIME_DELTA; turn_time_t ct = turn_time(); if(!turn_time_before(ct,to)) { TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "oAuth token is too old\n"); return -1; } if(max_session_time) { *max_session_time = to - ct; } } ns_bcopy(dot.enc_block.mac_key,key,dot.enc_block.key_length); ret = 0; } } }