/* Copyright(C) 2007-2018 VoIP objects (voipobjects.com) * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "ICERelaying.h" #include "ICEStunAttributes.h" #include "ICETime.h" #include "ICEMD5.h" #include "ICELog.h" #include "ICEStream.h" #include using namespace ice; #define LOG_SUBSYSTEM "ice" // ------------------ ClientAllocate ----------------- ClientAllocate::ClientAllocate(unsigned int lifetime) :AuthTransaction(), mLifetime(lifetime), mWireFamily(AF_INET), mAllocFamily(AF_INET) { assert(lifetime > 60 || !lifetime); setComment("ClientAllocate"); addLongTermCredentials(true); } ClientAllocate::~ClientAllocate() { } NetworkAddress& ClientAllocate::relayedAddress() { return mRelayedAddr; } NetworkAddress& ClientAllocate::reflexiveAddress() { return mReflexiveAddr; } NetworkAddress& ClientAllocate::responseAddress() { return mResponseAddr; } void ClientAllocate::setInitialRequest(StunMessage& msg) { if (keepalive()) { // Build refresh request msg.setMessageType(ice::StunMessage::Refresh); msg.setMessageClass(StunMessage::RequestClass); } else { // Build allocate request msg.setMessageClass(StunMessage::RequestClass); msg.setMessageType(StunMessage::Allocate); // Add UDP transport attribute (RequestedTransport is UDP by default) msg.setAttribute(new RequestedTransport()); // Add request family attribute if (mAllocFamily != mWireFamily) msg.setAttribute(new RequestedAddressFamily(mAllocFamily == AF_INET ? IPv4 : IPv6)); } } void ClientAllocate::setAuthenticatedRequest(StunMessage& msg) { if (keepalive()) { // Build refresh request msg.setMessageType(ice::StunMessage::Refresh); msg.setMessageClass(StunMessage::RequestClass); msg.lifetimeAttr().setLifetime(mLifetime); } else { msg.setMessageClass(StunMessage::RequestClass); msg.setMessageType(StunMessage::Allocate); // Add UDP transport attribute msg.setAttribute(new RequestedTransport()); // Add LIFETIME msg.lifetimeAttr().setLifetime(mLifetime); // Add request family attribute if (mAllocFamily != mWireFamily) msg.setAttribute(new RequestedAddressFamily(mAllocFamily == AF_INET ? IPv4 : IPv6)); } } void ClientAllocate::processSuccessMessage(StunMessage& msg, NetworkAddress& sourceAddress) { if (msg.hasAttribute(StunAttribute::XorMappedAddress)) mReflexiveAddr = msg.xorMappedAddressAttr().address(); if (msg.hasAttribute(StunAttribute::XorRelayedAddress)) mRelayedAddr = msg.xorRelayedAddressAttr().address(); if (msg.hasAttribute(StunAttribute::Lifetime)) mLifetime = msg.lifetimeAttr().lifetime(); mResponseAddr = sourceAddress; ICELogDebug(<< "Allocated for " << (int)mLifetime << " seconds."); } int ClientAllocate::lifetime() { return mLifetime; } void ClientAllocate::setWireFamily(int family) { mWireFamily = family; } int ClientAllocate::getWireFamily() const { return mWireFamily; } void ClientAllocate::setAllocFamily(int family) { mAllocFamily = family; } int ClientAllocate::getAllocFamily() const { return mAllocFamily; } //------------------- ClientRefresh ------------------------------- ClientRefresh::ClientRefresh(unsigned int lifetime, Stream* stream, ClientAllocate* allocate) :AuthTransaction(), mLifetime(lifetime), mStream(stream) { assert(stream); setComment("ClientRefresh"); addLongTermCredentials(true); // Copy data from Allocate transaction if (allocate) { setDestination( allocate->destination() ); setPassword( stream->mConfig.mTurnPassword ); setUsername( stream->mConfig.mTurnUsername ); setComponent( allocate->component() ); #ifdef ICE_CACHE_REALM_NONCE setRealm( allocate->realm() ); setNonce( allocate->nonce() ); #endif mRelayed = allocate->relayedAddress(); mReflexive = allocate->reflexiveAddress(); } } ClientRefresh::~ClientRefresh() { } void ClientRefresh::setInitialRequest(StunMessage& msg) { ICELogDebug(<< "Prepare to run ClientRefresh on TURN server with lifetime " << mLifetime); msg.setMessageType(ice::StunMessage::Refresh); msg.setMessageClass(ice::StunMessage::RequestClass); } void ClientRefresh::setAuthenticatedRequest(StunMessage& msg) { msg.setMessageType(StunMessage::Refresh); msg.setMessageClass(StunMessage::RequestClass); msg.lifetimeAttr().setLifetime(mLifetime); } void ClientRefresh::processSuccessMessage(StunMessage& /*msg*/, NetworkAddress& /*sourceAddress*/) { if (mLifetime) { ICELogDebug(<< "TURN allocation refreshed for " << (int)mLifetime << " seconds."); } else { if (mStream) { if (mStream->mTurnAllocated > 0) mStream->mTurnAllocated--; } ICELogDebug(<< "TURN allocation is deleted."); } } void ClientRefresh::processError() { if (mStream) { if (!mLifetime) { if (mStream->mTurnAllocated > 0) mStream->mTurnAllocated--; ICELogError(<< "TURN allocation is not deleted due to error " << errorCode() << " " << errorResponse()); } else ICELogError(<< "ClientRefresh failed due to error " << errorCode() << " " << errorResponse()); } } NetworkAddress ClientRefresh::relayedAddress() { return mRelayed; } NetworkAddress ClientRefresh::reflexiveAddress() { return mReflexive; } //------------------- ClientChannelBind ---------------------------- static TurnPrefix GPrefix = 0; static Mutex GPrefixGuard; static TurnPrefix obtainNewPrefix() { Lock l(GPrefixGuard); // Generate initial value if needed if (!GPrefix) GPrefix = (rand() % (0x7FFE - 0x4000)) + 0x4000; // Avoid logical overflow if (GPrefix == 0x7FFE) GPrefix = 0x4000; return ++GPrefix; } ClientChannelBind::ClientChannelBind(const NetworkAddress& address) :AuthTransaction(), mPeerAddress(address) { setComment( "ClientChannelBind" ); // Compute prefix mChannelPrefix = obtainNewPrefix(); ICELogInfo(<< "Channel prefix for TURN channel bind is " << mChannelPrefix); addLongTermCredentials(true); } ClientChannelBind::~ClientChannelBind() { } void ClientChannelBind::setInitialRequest(StunMessage& msg) { msg.setMessageClass(StunMessage::RequestClass); msg.setMessageType(StunMessage::ChannelBind); msg.channelNumberAttr().setChannelNumber(mChannelPrefix); msg.xorPeerAddressAttr().address() = mPeerAddress; } void ClientChannelBind::setAuthenticatedRequest(StunMessage& msg) { setInitialRequest(msg); } unsigned short ClientChannelBind::channelPrefix() { return mChannelPrefix; } bool ClientChannelBind::processData(StunMessage& msg, NetworkAddress& address) { return AuthTransaction::processData(msg, address); } void ClientChannelBind::processSuccessMessage(StunMessage& msg, NetworkAddress& sourceAddress) { ICELogDebug(<< mPeerAddress.toStdString() << " is bound to " << mChannelPrefix); // Make this transaction keepalive setKeepalive( true ); setType( KeepAlive ); setInterval( ICE_PERMISSIONS_REFRESH_INTERVAL ); setTimestamp( ICETimeHelper::timestamp() ); } void ClientChannelBind::processError() { ICELogCritical(<< "Failed to bind channel with error " << errorCode()); } NetworkAddress ClientChannelBind::peerAddress() { return mPeerAddress; } //----------------- ClientCreatePermission ------------------------ ClientCreatePermission::ClientCreatePermission() :AuthTransaction() { setComment("ClientCreatePermission"); addLongTermCredentials(true); } ClientCreatePermission::~ClientCreatePermission() { ; } void ClientCreatePermission::addIpAddress(const NetworkAddress& ip) { // Skip loopback / empty / LAN / IPv6 addresses addresses if (!ip.isLoopback() && !ip.isEmpty() && !ip.isLAN() && ip.family() == AF_INET) { for (unsigned i=0; iaddress() = mIPAddressList[i]; msg.addAttribute(xpa); } } void ClientCreatePermission::setAuthenticatedRequest(StunMessage& msg) { setInitialRequest(msg); } ClientCreatePermission::IpList& ClientCreatePermission::ipList() { return mIPAddressList; } // ------------------ SendIndication ---------------------------------- SendIndication::SendIndication() { } SendIndication::~SendIndication() { } void SendIndication::setTarget(NetworkAddress& addr) { mTarget = addr; } NetworkAddress& SendIndication::target() { return mTarget; } void SendIndication::setPlainData(ByteBuffer& plain) { mPlainData = plain; } ByteBuffer& SendIndication::plainData() { return mPlainData; } ByteBuffer* SendIndication::buildPacket() { StunMessage m; m.setMessageClass(StunMessage::IndicationClass); m.setMessageType(StunMessage::Send); XorPeerAddress* xpa = new XorPeerAddress(); xpa->address() = mTarget; DataAttribute* da = new DataAttribute(); da->setData(mPlainData); m.setAttribute(xpa); m.setAttribute(da); ByteBuffer* result = new ByteBuffer(); m.buildPacket(*result, ""); return result; } ByteBuffer* SendIndication::buildPacket(NetworkAddress& target, ByteBuffer& data, NetworkAddress& relay, int component) { SendIndication si; si.setTarget( target ); si.setPlainData( data ); ByteBuffer* result = si.buildPacket(); result->setComponent( component ); result->setRemoteAddress( relay ); return result; }