diff --git a/.travis.yml b/.travis.yml index 61f9bdd..10bb8b1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,6 +18,7 @@ addons: packages: - cmake - cmake-data + - libbsd-dev before_install: - export PATH=$HOME/.local/bin:$PATH - pip install cpp-coveralls --user `whoami` diff --git a/include/stun_intern.h b/include/stun_intern.h index 9264769..16cd89a 100644 --- a/include/stun_intern.h +++ b/include/stun_intern.h @@ -74,6 +74,7 @@ typedef struct { DiscussData* discussData; /*NULL allowed if none present */ bool addSoftware; bool stuntrace; + bool addTransCnt; } StunBindReqStruct; struct StunClientStats @@ -102,11 +103,6 @@ typedef struct uint32_t inst; StunBindReqStruct stunBindReq; - uint8_t stunReqMsgBuf[STUN_MAX_PACKET_SIZE]; /* encoded STUN request - * */ - int stunReqMsgBufLen; /* of encoded STUN - * request */ - STUN_USER_CREDENTIALS userCredentials; bool authenticated; @@ -117,13 +113,18 @@ typedef struct int32_t TimerRetransmit; uint32_t retransmits; + uint32_t reqTransCnt; + uint32_t respTransCnt; + /* RTT Info */ struct timeval start[STUNCLIENT_MAX_RETRANSMITS]; struct timeval stop[STUNCLIENT_MAX_RETRANSMITS]; + + /* icmp */ uint32_t ICMPtype; - uint32_t ttl; + /* uint32_t ttl; */ /* DISCUSS */ bool hasDiscuss; diff --git a/include/stunclient.h b/include/stunclient.h index 2ed0be5..e630b22 100644 --- a/include/stunclient.h +++ b/include/stunclient.h @@ -63,6 +63,8 @@ typedef struct struct sockaddr_storage dstBaseAddr; /* The destination seen from the * sender of the response */ uint32_t rtt; /* Rtt in microseconds */ + uint32_t reqTransCnt; + uint32_t respTransCnt; uint32_t retransmits; uint32_t ICMPtype; uint32_t ttl; @@ -180,7 +182,7 @@ StunClient_startBindTransaction(STUN_CLIENT_DATA* clientData, STUN_SENDFUNC sendFunc, STUNCB stunCbFunc, DiscussData* discussData); -uint32_t +void StunClient_startSTUNTrace(STUN_CLIENT_DATA* clientData, void* userCtx, const struct sockaddr* serverAddr, @@ -230,27 +232,6 @@ StunClient_cancelBindingTransaction(STUN_CLIENT_DATA* clientData, StunMsgId transactionId); -/********* Server handling: send STUN BIND RESP *************/ -bool -StunServer_SendConnectivityBindingResp(STUN_CLIENT_DATA* clientData, - int32_t globalSocketId, - StunMsgId transactionId, - const char* password, - const struct sockaddr* mappedAddr, - const struct sockaddr* dstAddr, - void* userData, - STUN_SENDFUNC sendFunc, - int proto, - bool useRelay, - uint32_t responseCode, - DiscussData* discussData); - -/********** Server handling: incoming STUN BIND REQ **********/ -bool -StunServer_HandleStunIncomingBindReqMsg(STUN_CLIENT_DATA* clientData, - STUN_INCOMING_REQ_DATA* pReq, - const StunMessage* stunMsg, - bool fromRelay); void StunClient_clearStats(STUN_CLIENT_DATA* clientData); diff --git a/include/stunlib.h b/include/stunlib.h index 4d7f711..cc3a1c5 100644 --- a/include/stunlib.h +++ b/include/stunlib.h @@ -116,6 +116,9 @@ extern "C" { #define STUN_ATTR_ICEControlled 0x8029 #define STUN_ATTR_ICEControlling 0x802A +/* Draft loss and RTT calculation TODO:update actual calues*/ +#define STUN_ATTR_TransCount 0x8072 + /** IP Addr family **/ #define STUN_ADDR_IPv4Family 0x01 #define STUN_ADDR_IPv6Family 0x02 @@ -188,6 +191,7 @@ extern "C" { * * * + * *msec **/ #define STUNCLIENT_DFLT_TICK_TIMER_MS 50 @@ -362,6 +366,14 @@ typedef struct } StunAtrNetworkStatus; +typedef struct +{ + uint16_t reserved; + uint8_t reqCnt; + uint8_t respCnt; +} +StunAtrTransCount; + typedef struct { uint32_t first; @@ -542,7 +554,8 @@ typedef struct bool hasCiscoNetFeedResp; StunAtrCiscoNetworkFeedback ciscoNetFeedResp; - + bool hasTransCount; + StunAtrTransCount transCount; /* No value, only flaged */ bool hasUseCandidate; @@ -575,6 +588,11 @@ typedef void (* STUN_ERR_FUNC)(const char* fmt, ***** API Funcs ****** **********************/ +/* transaction id compare */ +bool +stunlib_transIdIsEqual(const StunMsgId* a, + const StunMsgId* b); + /***********************************************/ /************* Decode functions ***************/ /***********************************************/ @@ -846,9 +864,8 @@ stunlib_printBuffer(FILE* stream, void -stunlib_createId(StunMsgId* pId, - long randval, - unsigned char retries); +stunlib_createId(StunMsgId* pId); + bool stunlib_addRealm(StunMessage* stunMsg, const char* realm, diff --git a/include/stunserver.h b/include/stunserver.h new file mode 100644 index 0000000..2494e04 --- /dev/null +++ b/include/stunserver.h @@ -0,0 +1,51 @@ + + +#ifndef STUNSERVER_H +#define STUNSERVER_H + + +#include "stunlib.h" /* stun enc/dec and msg formats*/ +#include +#include "sockaddr_util.h" +#include "stunclient.h" +#include "stun_intern.h" + +#ifdef __cplusplus +extern "C" { +#else +#include +#endif + + bool + CreateConnectivityBindingResp(StunMessage * stunMsg, + StunMsgId transactionId, + const struct sockaddr* mappedSockAddr, + uint8_t reqTrnspCnt, + uint8_t respTrnspCnt, + uint16_t response, + uint32_t responseCode, + DiscussData * discussData); +/********* Server handling: send STUN BIND RESP *************/ + bool + StunServer_SendConnectivityBindingResp(STUN_CLIENT_DATA * clientData, + int32_t globalSocketId, + StunMsgId transactionId, + const char* password, + const struct sockaddr* mappedAddr, + const struct sockaddr* dstAddr, + uint8_t reqTrnspCnt, + uint8_t respTrnspCnt, + void* userData, + STUN_SENDFUNC sendFunc, + int proto, + bool useRelay, + uint32_t responseCode, + DiscussData * discussData); + +/********** Server handling: incoming STUN BIND REQ **********/ + bool + StunServer_HandleStunIncomingBindReqMsg(STUN_CLIENT_DATA * clientData, + STUN_INCOMING_REQ_DATA * pReq, + const StunMessage * stunMsg, + bool fromRelay); +#endif diff --git a/include/stuntrace.h b/include/stuntrace.h index d83f4ea..0be12b5 100644 --- a/include/stuntrace.h +++ b/include/stuntrace.h @@ -62,7 +62,7 @@ struct hiutResult { /* Initial Length of first STUN packet (TTL=1) */ - uint32_t stunLen; + /* uint32_t stunLen; */ struct hiutPathElement pathElement[MAX_TTL + 1]; bool remoteAlive; /* struct hiutTTLinfo ttlInfo[MAX_TTL]; */ diff --git a/include/turn_intern.h b/include/turn_intern.h index 57e811a..36aa9af 100644 --- a/include/turn_intern.h +++ b/include/turn_intern.h @@ -14,7 +14,7 @@ extern "C" { /* make sure both the following timers are < 5 minutes */ #define TURN_REFRESH_CHANNEL_TIMER_SEC (3 * 60) /* 3 min (spec. is 10 min) - **/ + **/ #define TURN_REFRESH_PERMISSION_TIMER_SEC (4 * 60) /* 4 min (spec. is 5 min) * */ @@ -103,19 +103,21 @@ struct TURN_INSTANCE_DATA unsigned long id; TURN_INFO_FUNC infoFunc; - TURN_STATE state; - bool inUse; - TurnAllocateReqStuct turnAllocateReq; - StunMsgId StunReqTransId; /* transaction - *id of request + TURN_STATE state; + bool inUse; + TurnAllocateReqStuct turnAllocateReq; + StunMsgId StunReqTransId; /* transaction + * id of + *request **/ - StunMsgId PrevRespTransId; /* transaction - *id of last - *received */ - uint8_t stunReqMsgBuf[STUN_MAX_PACKET_SIZE]; /* encoded STUN - *request */ - int stunReqMsgBufLen; /* of encoded - *STUN request + StunMsgId PrevRespTransId; /* transaction + * id of last + * received */ + uint8_t stunReqMsgBuf[STUN_MAX_PACKET_SIZE]; /* encoded STUN + * request + * */ + int stunReqMsgBufLen; /* of encoded + * STUN request **/ bool pendingChannelBind; STUN_USER_CREDENTIALS userCredentials; diff --git a/include/turnclient.h b/include/turnclient.h index 1a15f08..b8f82a1 100644 --- a/include/turnclient.h +++ b/include/turnclient.h @@ -5,7 +5,7 @@ #define TURNCLIENT_H -//#include +/* #include */ #include #include "stunlib.h" /* stun enc/dec and msg formats*/ @@ -18,7 +18,7 @@ extern "C" { enum { TURN_DFLT_PORT = 3478, TURN_MAX_PERMISSION_PEERS = 12 /* max. number of Peers in a - *createPermissionRequest */ + * createPermissionRequest */ }; @@ -34,34 +34,34 @@ typedef enum TurnResult_AllocOk, /* Turn allocation was successful */ TurnResult_AllocFail, /* Turn Allocation failed */ TurnResult_AllocFailNoAnswer, /* Turn Allocation failed - no - *contact with turn server */ + * contact with turn server */ TurnResult_AllocUnauthorised, /* passwd/username is incorrect */ TurnResult_CreatePermissionOk, /* successfull CreatePermission */ TurnResult_CreatePermissionFail, /* Failed CreatePermission - no - *contact with turn server */ + * contact with turn server */ TurnResult_CreatePermissionNoAnswer, /* CreatePermission failed */ TurnResult_CreatePermissionQuotaReached, /* Quouta reached */ TurnResult_PermissionRefreshFail, /* Refresh Permission failed */ TurnResult_ChanBindOk, /* successful Channel Bind */ TurnResult_ChanBindFail, /* Channel Bind failed */ TurnResult_ChanBindFailNoanswer, /* Channel bind failed - no contact - *with turn server */ + * with turn server */ TurnResult_RefreshFail, /* Allocation Refresh failed */ TurnResult_RefreshFailNoAnswer, /* Allocation Refresh failed */ TurnResult_RelayReleaseComplete, /* Relay has been sucessfully - *released */ + * released */ TurnResult_RelayReleaseFailed, /* Relay released failed */ TurnResult_InternalError, TurnResult_MalformedRespWaitAlloc /* server problem occurred when - *waiting for alloc resp */ + * waiting for alloc resp */ } TurnResult_T; /* * Result of successful Turn allocation (TurnResult_AllocOk) has the following - *format. + * format. * srflxAddr - Server Reflexive Address/port. This is source addr/port of - *the AllocateRequest as seen by the turn server + * the AllocateRequest as seen by the turn server * relAddr - Relay Address/Port. As allocated on the turn server. */ typedef struct @@ -75,7 +75,7 @@ typedef struct /* Signalled back to the caller as a parameter in the TURN callback (see TURNCB) - **/ +**/ typedef struct { TurnResult_T turnResult; @@ -114,27 +114,27 @@ TurnStats_T; /* Defines how a user of turn sends data on e.g. socket */ typedef void (* TURN_SEND_FUNC)(const uint8_t* buffer, /* ptr to - *buffer to - *send */ + * buffer to + * send */ size_t bufLen, /* length of - *send - *buffer */ + * send + * buffer */ const struct sockaddr* dstAddr, /* Optional, - *if - *connected - *to socket + * if + * connected + * to socket **/ void* userCtx); /* context - - *e.g. - *socket - *handle */ + * e.g. + * socket + * handle */ /* Signalling back to user e.g. result of AllocateResp, ChanBindResp etc... * userCtx - User provided context, as provided in - *TurnClient_startAllocateTransaction(userCtx,...) + * TurnClient_startAllocateTransaction(userCtx,...) * TurnCbData - User provided turn callback data. Turn writes status here. - *e.g. Alloc ok + reflexive + relay address + * e.g. Alloc ok + reflexive + relay address */ typedef void (* TURN_CB_FUNC)(void* userCtx, TurnCallBackData_T* turnCbData); @@ -149,27 +149,27 @@ typedef void (* TURN_INFO_FUNC)(void* userCtx, * Initiate a Turn Allocate Transaction * instance - instance data * tickMsec - Tells turnclient how often TurnClient_HandleTick() is - *called. + * called. * funcPtr - Will be called by Turn when it outputs management - *info and trace. + * info and trace. * SwVerStr - Software version string to be sent in TURN Requests* * turnServerAddr - Address of TURN server * userName - \0 terminated string. Max - *STUN_MSG_MAX_USERNAME_LENGTH-1 chars. + * STUN_MSG_MAX_USERNAME_LENGTH-1 chars. * password - \0 terminated string. Max - *STUN_MSG_MAX_PASSWORD_LENGTH-1 chars. + * STUN_MSG_MAX_PASSWORD_LENGTH-1 chars. * ai_family - requested address family (AF_INET or AF_INET6) * sendFunc - function used to send STUN packet. - *send(sockhandle,buff, len, turnServerAddr, userCtx) + * send(sockhandle,buff, len, turnServerAddr, userCtx) * turnCbFunc - user provided callback function used by turn to - *signal the result of an allocation or channel bind etc... + * signal the result of an allocation or channel bind etc... * TurnCbData - user provided callback turn data. turn writes to this - *data area. + * data area. * evenPortAndReserve - reserve an even port n and next port n+1 * reservationToken - request a previously reserved port for the allocation * returns - Turn instance/context. Application should store this - *in further calls to TurnClient_StartChannelBindReq(), - *TurnClient_HandleIncResp(). + * in further calls to TurnClient_StartChannelBindReq(), + * TurnClient_HandleIncResp(). */ bool TurnClient_StartAllocateTransaction(TURN_INSTANCE_DATA** instp, @@ -200,15 +200,15 @@ TurnClient_StartChannelBindReq(TURN_INSTANCE_DATA* inst, /* * Create a permission in turn server. i.e. CreatePermission(List of - *RemotePeers). + * RemotePeers). * This will enable the turn server to route DataIndicatins from the Remote - *peers. + * peers. * * instance - instance pointer * noOfPeers - Number of peer addresses in peerTrnspAddrStr string * array * peerTrnspAddrStr - Pointer to array of strings in format "a.b.c.d:port". - *Note - Port is not used in create permission. + * Note - Port is not used in create permission. * */ bool @@ -255,7 +255,7 @@ TurnClient_SendPacket(TURN_INSTANCE_DATA* inst, uint32_t dataLen, uint32_t offset, const struct sockaddr* peerAddr, - bool needChannelDataPadding); + bool needChannelDataPadding); /* * handle received turn packets @@ -280,8 +280,10 @@ TurnClient_HandleIncResp(TURN_INSTANCE_DATA* inst, StunMessage* msg, uint8_t* buf); -bool TurnClient_hasBeenRedirected(TURN_INSTANCE_DATA *pInst); -const struct sockaddr * TurnClient_getRedirectedServerAddr(TURN_INSTANCE_DATA *pInst); +bool +TurnClient_hasBeenRedirected(TURN_INSTANCE_DATA* pInst); +const struct sockaddr* +TurnClient_getRedirectedServerAddr(TURN_INSTANCE_DATA* pInst); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4c0d68a..a6217f6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,6 +4,7 @@ set ( stunlib_srcs stunclient.c + stunserver.c stunlib.c turnclient.c stuntrace.c @@ -36,6 +37,10 @@ if( OPENSSL_FOUND ) list(APPEND ADDITIONAL_LIBS ${OPENSSL_LIBRARIES}) endif( OPENSSL_FOUND ) +# Todo fix propper library discovery. +if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + list(APPEND ADDITIONAL_LIBS "bsd") +endif() target_link_libraries ( stunlib PRIVATE sockaddrutil ${ADDITIONAL_LIBS}) diff --git a/src/stunclient.c b/src/stunclient.c index 10ac714..53bcb10 100644 --- a/src/stunclient.c +++ b/src/stunclient.c @@ -32,6 +32,7 @@ #include #include "stunclient.h" + #include "stun_intern.h" @@ -132,16 +133,6 @@ StunMsgToInternalStunSig(const StunMessage* msg) } -/* transaction id compare */ -static bool -TransIdIsEqual(const StunMsgId* a, - const StunMsgId* b) -{ - return (memcmp(a, b, STUN_MSG_ID_SIZE) == 0); -} - - - static void StoreStunBindReq(STUN_TRANSACTION_DATA* trans, StunBindReqStruct* pMsgIn) @@ -223,6 +214,14 @@ BuildStunBindReq(STUN_TRANSACTION_DATA* trans, { stunlib_addSoftware(stunReqMsg, SoftwareVersionStr, STUN_DFLT_PAD); } + + if (trans->stunBindReq.addTransCnt) + { + stunReqMsg->hasTransCount = true; + stunReqMsg->transCount.reserved = (uint16_t)0; + stunReqMsg->transCount.reqCnt = (uint8_t)trans->retransmits + 1; + stunReqMsg->transCount.respCnt = (uint8_t)0; + } } @@ -355,6 +354,8 @@ StunClient_startBindTransaction(STUN_CLIENT_DATA* clientData, m.discussData = discussData; m.addSoftware = true; + /*TODO: Let app overide this */ + m.addTransCnt = true; /* callback and data (owned by caller) */ m.stunCbFunc = stunCbFunc; @@ -364,7 +365,7 @@ StunClient_startBindTransaction(STUN_CLIENT_DATA* clientData, return 0; } -uint32_t +void StunClient_startSTUNTrace(STUN_CLIENT_DATA* clientData, void* userCtx, const struct sockaddr* serverAddr, @@ -384,8 +385,6 @@ StunClient_startSTUNTrace(STUN_CLIENT_DATA* clientData, StunBindReqStruct m; STUN_TRANSACTION_DATA trans; StunMessage stunMsg; - uint8_t stunBuff[STUN_MAX_PACKET_SIZE]; - uint32_t len; memset( &m, 0, sizeof(m) ); m.userCtx = userCtx; @@ -402,20 +401,15 @@ StunClient_startSTUNTrace(STUN_CLIENT_DATA* clientData, m.discussData = discussData; m.addSoftware = false; /* callback and data (owned by caller) */ - m.stunCbFunc = stunCbFunc; - m.stuntrace = true; + m.stunCbFunc = stunCbFunc; + m.stuntrace = true; + m.addTransCnt = false; + StoreStunBindReq(&trans, &m); BuildStunBindReq(&trans, &stunMsg); StunClientMain(clientData, STUNCLIENT_CTX_UNKNOWN, STUN_SIGNAL_BindReq, (uint8_t*)&m); - len = stunlib_encodeMessage(&stunMsg, - (uint8_t*)stunBuff, - STUN_MAX_PACKET_SIZE, - (unsigned char*)password, /* md5key */ - password ? strlen(password) : 0, /* keyLen */ - NULL); - return len; } @@ -433,7 +427,8 @@ StunClient_HandleIncResp(STUN_CLIENT_DATA* clientData, { STUN_TRANSACTION_DATA* trans = &clientData->data[i]; if ( trans->inUse && - TransIdIsEqual(&msg->msgHdr.id, &trans->stunBindReq.transactionId) ) + stunlib_transIdIsEqual(&msg->msgHdr.id, + &trans->stunBindReq.transactionId) ) { StunRespStruct m; gettimeofday(&trans->stop[trans->retransmits], NULL); @@ -473,8 +468,8 @@ StunClient_HandleICMP(STUN_CLIENT_DATA* clientData, { STUN_TRANSACTION_DATA* trans = &clientData->data[i]; if ( trans->inUse && - TransIdIsEqual(&clientData->traceResult.currStunMsgId, - &trans->stunBindReq.transactionId) ) + stunlib_transIdIsEqual(&clientData->traceResult.currStunMsgId, + &trans->stunBindReq.transactionId) ) { StunRespStruct m; gettimeofday(&trans->stop[trans->retransmits], NULL); @@ -518,7 +513,8 @@ StunClient_cancelBindingTransaction(STUN_CLIENT_DATA* clientData, { STUN_TRANSACTION_DATA* trans = &clientData->data[i]; if ( trans->inUse && - TransIdIsEqual(&transactionId, &trans->stunBindReq.transactionId) ) + stunlib_transIdIsEqual(&transactionId, + &trans->stunBindReq.transactionId) ) { StunClientMain(clientData, i, STUN_SIGNAL_Cancel, NULL); return i; @@ -529,275 +525,8 @@ StunClient_cancelBindingTransaction(STUN_CLIENT_DATA* clientData, } -static bool -CreateConnectivityBindingResp(StunMessage* stunMsg, - StunMsgId transactionId, - const struct sockaddr* mappedSockAddr, - uint16_t response, - uint32_t responseCode, - DiscussData* discussData) -{ - StunIPAddress mappedAddr; - - if ( !sockaddr_isSet(mappedSockAddr) ) - { - return false; - } - - memset(stunMsg, 0, sizeof *stunMsg); - stunMsg->msgHdr.msgType = response; - - if (mappedSockAddr->sa_family == AF_INET) - { - mappedAddr.familyType = STUN_ADDR_IPv4Family; - mappedAddr.addr.v4.port = ntohs( - ( (struct sockaddr_in*)mappedSockAddr )->sin_port); - mappedAddr.addr.v4.addr = ntohl( - ( (struct sockaddr_in*)mappedSockAddr )->sin_addr.s_addr); - - } - else if (mappedSockAddr->sa_family == AF_INET6) - { - mappedAddr.familyType = STUN_ADDR_IPv6Family; - mappedAddr.addr.v6.port = ntohs( - ( (struct sockaddr_in6*)mappedSockAddr )->sin6_port); - - /*TODO: will this be correct ? */ - memcpy( mappedAddr.addr.v6.addr, - ( (struct sockaddr_in6*)mappedSockAddr )->sin6_addr.s6_addr, - sizeof(mappedAddr.addr.v6.addr) ); - } - else - { - return false; - } - - /*id*/ - stunMsg->msgHdr.id = transactionId; - - /* The XOR address MUST be added according to the RFC */ - stunMsg->hasXorMappedAddress = true; - stunMsg->xorMappedAddress = mappedAddr; - - if (discussData != NULL) - { - stunMsg->hasStreamType = true; - stunMsg->streamType.type = discussData->streamType; - stunMsg->streamType.interactivity = discussData->interactivity; - - stunMsg->hasNetworkStatus = true; - stunMsg->networkStatus.flags = 0; - stunMsg->networkStatus.nodeCnt = 0; - stunMsg->networkStatus.upMaxBandwidth = 0; - stunMsg->networkStatus.downMaxBandwidth = 0; - - stunMsg->hasNetworkStatusResp = true; - stunMsg->networkStatusResp.flags = - discussData->networkStatusResp_flags; - stunMsg->networkStatusResp.nodeCnt = - discussData->networkStatusResp_nodeCnt; - stunMsg->networkStatusResp.upMaxBandwidth = - discussData->networkStatusResp_upMaxBandwidth; - stunMsg->networkStatusResp.downMaxBandwidth = - discussData->networkStatusResp_downMaxBandwidth; - } - if (responseCode != 200) - { - stunMsg->hasErrorCode = true; - stunMsg->errorCode.errorClass = responseCode / 100; - stunMsg->errorCode.number = (uint8_t) (responseCode % 100); - if (responseCode == 487) - { - strncpy( stunMsg->errorCode.reason, "Role Conflict", - sizeof (stunMsg->errorCode.reason) ); - stunMsg->errorCode.sizeReason = strlen(stunMsg->errorCode.reason); - } - else if (responseCode == 400) - { - strncpy( stunMsg->errorCode.reason, "Bad Request", - sizeof (stunMsg->errorCode.reason) ); - stunMsg->errorCode.sizeReason = strlen(stunMsg->errorCode.reason); - } - } - - return true; -} - - -static bool -SendConnectivityBindResponse(STUN_CLIENT_DATA* clientData, - int32_t globalSocketId, - StunMessage* stunRespMsg, - const char* password, - const struct sockaddr* dstAddr, - void* userData, - STUN_SENDFUNC sendFunc, - int proto, - bool useRelay) -{ - uint8_t stunBuff[STUN_MAX_PACKET_SIZE]; - int stunLen; - - (void) userData; - /* encode bind Response */ - stunLen = stunlib_encodeMessage(stunRespMsg, - (uint8_t*)stunBuff, - STUN_MAX_PACKET_SIZE, - (unsigned char*)password, /* md5key - **/ - password ? strlen(password) : 0, /* keyLen - **/ - NULL); - if (!stunLen) - { - StunPrint(clientData->logUserData, - clientData->Log_cb, - StunInfoCategory_Error, - " Failed to encode Binding request response\n"); - return false; - } - - /* send */ - /* sendFunc(globalSocketId, stunBuff, stunLen, dstAddr, useRelay, 0); */ - sendFunc(clientData->userCtx, - globalSocketId, - stunBuff, - stunLen, - dstAddr, - proto, - useRelay, - 0); - clientData->stats.BindRespSent++; - return true; -} - - -/********* Server handling of STUN BIND RESP *************/ -bool -StunServer_SendConnectivityBindingResp(STUN_CLIENT_DATA* clientData, - int32_t globalSocketId, - StunMsgId transactionId, - const char* password, - const struct sockaddr* mappedAddr, - const struct sockaddr* dstAddr, - void* userData, - STUN_SENDFUNC sendFunc, - int proto, - bool useRelay, - uint32_t responseCode, - DiscussData* discussData) -{ - StunMessage stunRespMsg; - - /* format */ - if ( CreateConnectivityBindingResp(&stunRespMsg, - transactionId, - mappedAddr, - (responseCode == - 200) ? STUN_MSG_BindResponseMsg : - STUN_MSG_BindErrorResponseMsg, - responseCode, - discussData) ) - { - /* encode and send */ - if ( SendConnectivityBindResponse(clientData, - globalSocketId, - &stunRespMsg, - password, - dstAddr, - userData, - sendFunc, - proto, - useRelay) ) - { - return true; - } - } - return false; -} - - -/********** Server handling of incoming STUN BIND REQ **********/ -bool -StunServer_HandleStunIncomingBindReqMsg(STUN_CLIENT_DATA* clientData, - STUN_INCOMING_REQ_DATA* pReq, - const StunMessage* stunMsg, - bool fromRelay) -{ - if (!clientData) - { - return false; - } - - memcpy( &pReq->transactionId, &stunMsg->msgHdr.id, sizeof(StunMsgId) ); - - pReq->fromRelay = fromRelay; - - if (stunMsg->hasUsername) - { - strncpy( pReq->ufrag, stunMsg->username.value, - min(stunMsg->username.sizeValue, STUN_MAX_STRING) ); - if (stunMsg->username.sizeValue < STUN_MAX_STRING) - { - pReq->ufrag[stunMsg->username.sizeValue] = '\0'; - } - else - { - pReq->ufrag[STUN_MAX_STRING - 1] = '\0'; - } - } - else - { - StunPrint(clientData->logUserData, - clientData->Log_cb, - StunInfoCategory_Error, - " Missing Username in Binding Request\n"); - return false; - } - - if (stunMsg->hasPriority) - { - pReq->peerPriority = stunMsg->priority.value; - } - else - { - StunPrint(clientData->logUserData, - clientData->Log_cb, - StunInfoCategory_Error, - " Missing Priority in Binding Request\n"); - return false; - } - - pReq->useCandidate = stunMsg->hasUseCandidate; - - if (stunMsg->hasControlling) - { - pReq->iceControlling = true; - pReq->tieBreaker = stunMsg->controlling.value; - } - else - { - pReq->iceControlling = false; - } - - if (stunMsg->hasControlled) - { - pReq->iceControlled = true; - pReq->tieBreaker = stunMsg->controlled.value; - } - else - { - pReq->iceControlled = false; - } - if (fromRelay) - { - clientData->stats.BindReqReceived_ViaRelay++; - } - clientData->stats.BindReqReceived++; - return true; -} /*************************************************************************/ @@ -923,7 +652,7 @@ StartTimer(STUN_TRANSACTION_DATA* trans, { STUN_CLIENT_DATA* client = trans->client; - StunPrint(client->logUserData, client->Log_cb, StunInfoCategory_Trace, + StunPrint(client->logUserData, client->Log_cb, StunInfoCategory_Trace, " StartTimer(%s, %dms)", trans->inst, StunsigToStr(sig), durationMsec); @@ -948,7 +677,7 @@ StopTimer(STUN_TRANSACTION_DATA* trans, { STUN_CLIENT_DATA* client = trans->client; - StunPrint( client->logUserData, client->Log_cb, StunInfoCategory_Trace, + StunPrint( client->logUserData, client->Log_cb, StunInfoCategory_Trace, " StopTimer(%s)", trans->inst, StunsigToStr(sig) ); @@ -1033,36 +762,39 @@ SendStunReq(STUN_TRANSACTION_DATA* trans, StunMessage* stunReqMsg) { STUN_CLIENT_DATA* client = trans->client; + uint8_t stunReqMsgBuf[STUN_MAX_PACKET_SIZE]; /* encoded STUN request + * */ + int stunReqMsgBufLen; /* of encoded STUN + * request */ + /* encode the BindReq */ if (strlen(trans->stunBindReq.password) > 0) { - trans->stunReqMsgBufLen = stunlib_encodeMessage(stunReqMsg, - (unsigned char*) (trans-> - stunReqMsgBuf), - STUN_MAX_PACKET_SIZE, - (unsigned char*)&trans->stunBindReq.password, - /* key */ - strlen(trans->stunBindReq. - password), - /* keyLen - * */ - NULL); + stunReqMsgBufLen = stunlib_encodeMessage(stunReqMsg, + (unsigned char*) (stunReqMsgBuf), + STUN_MAX_PACKET_SIZE, + (unsigned char*)&trans->stunBindReq.password, + /* key */ + strlen(trans->stunBindReq. + password), + /* keyLen + * */ + NULL); } else { - trans->stunReqMsgBufLen = stunlib_encodeMessage(stunReqMsg, - (unsigned char*) (trans-> - stunReqMsgBuf), - STUN_MAX_PACKET_SIZE, - NULL, - /* key */ - 0, - /* keyLen */ - NULL); + stunReqMsgBufLen = stunlib_encodeMessage(stunReqMsg, + (unsigned char*) (stunReqMsgBuf), + STUN_MAX_PACKET_SIZE, + NULL, + /* key */ + 0, + /* keyLen */ + NULL); } - if (!trans->stunReqMsgBufLen) + if (!stunReqMsgBufLen) { StunPrint(client->logUserData, client->Log_cb, @@ -1073,13 +805,13 @@ SendStunReq(STUN_TRANSACTION_DATA* trans, } /*Store Time so we can messure RTT */ - gettimeofday(&trans->start[trans->retransmits], NULL); + gettimeofday(&trans->start[0], NULL); if (trans->stunBindReq.sendFunc != NULL) { trans->stunBindReq.sendFunc(trans->client->userCtx, trans->stunBindReq.sockhandle, - trans->stunReqMsgBuf, - trans->stunReqMsgBufLen, + stunReqMsgBuf, + stunReqMsgBufLen, (struct sockaddr*)&trans->stunBindReq.serverAddr, trans->stunBindReq.proto, trans->stunBindReq.useRelay, @@ -1117,13 +849,47 @@ StunClientFsm(STUN_TRANSACTION_DATA* trans, static void RetransmitLastReq(STUN_TRANSACTION_DATA* trans, + StunMessage* stunReqMsg, struct sockaddr_storage* destAddr) { - gettimeofday(&trans->start[trans->retransmits + 1], NULL); + + /* We need to recalculate Integrity Attribute due to the change in reqCnt*/ + /* encode the BindReq */ + uint8_t stunReqMsgBuf[STUN_MAX_PACKET_SIZE]; /* encoded STUN request + * */ + int stunReqMsgBufLen; /* of encoded STUN + * request */ + + if (strlen(trans->stunBindReq.password) > 0) + { + stunReqMsgBufLen = stunlib_encodeMessage(stunReqMsg, + (unsigned char*) (stunReqMsgBuf), + STUN_MAX_PACKET_SIZE, + (unsigned char*)&trans->stunBindReq.password, + /* key */ + strlen(trans->stunBindReq. + password), + /* keyLen + * */ + NULL); + } + else + { + stunReqMsgBufLen = stunlib_encodeMessage(stunReqMsg, + (unsigned char*) (stunReqMsgBuf), + STUN_MAX_PACKET_SIZE, + NULL, + /* key */ + 0, + /* keyLen */ + NULL); + + } + gettimeofday(&trans->start[trans->retransmits], NULL); trans->stunBindReq.sendFunc(trans->client->userCtx, trans->stunBindReq.sockhandle, - trans->stunReqMsgBuf, - trans->stunReqMsgBufLen, + stunReqMsgBuf, + stunReqMsgBufLen, (struct sockaddr*)destAddr, trans->stunBindReq.proto, trans->stunBindReq.useRelay, @@ -1163,6 +929,32 @@ StartNextRetransmitTimer(STUN_TRANSACTION_DATA* trans) } } +static int +getRTTvalue(STUN_TRANSACTION_DATA* trans) +{ + int32_t start, stop = 0; + + + if ( (trans->reqTransCnt > 0) && + (trans->reqTransCnt < STUNCLIENT_MAX_RETRANSMITS) ) + { + stop = (trans->stop[trans->reqTransCnt - 1].tv_sec * 1000000 + + trans->stop[trans->reqTransCnt - 1].tv_usec); + /* Always use the first stored value for start. */ + start = (trans->start[trans->reqTransCnt - 1].tv_sec * 1000000 + + trans->start[trans->reqTransCnt - 1].tv_usec); + } + else + { + stop = (trans->stop[trans->retransmits].tv_sec * 1000000 + + trans->stop[trans->retransmits].tv_usec); + /* Always use the first stored value for start. */ + start = (trans->start[0].tv_sec * 1000000 + + trans->start[0].tv_usec); + + } + return stop - start; +} static void CallBack(STUN_TRANSACTION_DATA* trans, @@ -1172,8 +964,10 @@ CallBack(STUN_TRANSACTION_DATA* trans, memset( &res, 0, sizeof (StunCallBackData_T) ); memcpy( &res.msgId, &trans->stunBindReq.transactionId, sizeof(StunMsgId) ); - res.stunResult = stunResult; - res.ttl = trans->stunBindReq.ttl; + res.stunResult = stunResult; + res.ttl = trans->stunBindReq.ttl; + res.rtt = getRTTvalue(trans); + res.retransmits = trans->retransmits; if (trans->stunBindReq.stunCbFunc) { @@ -1201,7 +995,7 @@ CommonRetryTimeoutHandler(STUN_TRANSACTION_DATA* trans, max = STUNCLIENT_MAX_RETRANSMITS; } - if ( (trans->retransmits < max) + if ( ( trans->retransmits < (max - 1) ) && (stunTimeoutList[trans->retransmits] != 0) ) /* can be 0 terminated if * using fewer * retransmits @@ -1213,10 +1007,13 @@ CommonRetryTimeoutHandler(STUN_TRANSACTION_DATA* trans, StunPrint(client->logUserData, client->Log_cb, StunInfoCategory_Trace, " Retrans %s Retry: %d to %s", - trans->inst, errStr, trans->retransmits + 1, peer); - RetransmitLastReq(trans, &trans->stunBindReq.serverAddr); - StartNextRetransmitTimer(trans); + trans->inst, errStr, trans->retransmits, peer); + StunMessage stunReqMsg; trans->retransmits++; + BuildStunBindReq(trans, &stunReqMsg); + RetransmitLastReq(trans, &stunReqMsg, &trans->stunBindReq.serverAddr); + StartNextRetransmitTimer(trans); + trans->stats.Retransmits++; } else @@ -1232,7 +1029,7 @@ static void CancelRetryTimeoutHandler(STUN_TRANSACTION_DATA* trans) { STUN_CLIENT_DATA* client = trans->client; - uint32_t max; + uint32_t max; if (trans->stunBindReq.stuntrace) { @@ -1251,6 +1048,7 @@ CancelRetryTimeoutHandler(STUN_TRANSACTION_DATA* trans) **/ { StartNextRetransmitTimer(trans); + trans->retransmits++; } else @@ -1290,8 +1088,6 @@ StoreBindResp(STUN_TRANSACTION_DATA* trans, resp->xorMappedAddress.addr.v6.addr, htons(resp->xorMappedAddress.addr.v6.port) ); } - - return true; } else { @@ -1300,21 +1096,16 @@ StoreBindResp(STUN_TRANSACTION_DATA* trans, trans->inst); return false; } -} - -static int -getRTTvalue(STUN_TRANSACTION_DATA* trans) -{ - int32_t stop = (trans->stop[trans->retransmits].tv_sec * 1000000 + - trans->stop[trans->retransmits].tv_usec); - /* Always use the first stored value for start. */ - int32_t start = (trans->start[0].tv_sec * 1000000 + - trans->start[0].tv_usec); - return stop - start; + if (resp->hasTransCount) + { + trans->reqTransCnt = resp->transCount.reqCnt; + trans->respTransCnt = resp->transCount.respCnt; + } + return true; +} -} static void BindRespCallback(STUN_TRANSACTION_DATA* trans, const struct sockaddr* srcAddr) @@ -1340,8 +1131,12 @@ BindRespCallback(STUN_TRANSACTION_DATA* trans, /* So did we loose a packet, or got an answer to the first response?*/ - res.rtt = getRTTvalue(trans); - res.ttl = trans->stunBindReq.ttl; + res.rtt = getRTTvalue(trans); + res.ttl = trans->stunBindReq.ttl; + res.retransmits = trans->retransmits; + + res.respTransCnt = trans->respTransCnt; + res.reqTransCnt = trans->reqTransCnt; StunPrint( client->logUserData, client->Log_cb, StunInfoCategory_Info, " BindResp from src: %s", @@ -1371,7 +1166,7 @@ ICMPRespCallback(STUN_TRANSACTION_DATA* trans, res.stunResult = StunResult_ICMPResp; res.ICMPtype = trans->ICMPtype; - res.ttl = trans->ttl; + res.ttl = trans->stunBindReq.ttl; res.rtt = getRTTvalue(trans); res.retransmits = trans->retransmits; @@ -1462,7 +1257,7 @@ StunState_WaitBindResp(STUN_TRANSACTION_DATA* trans, StunMessage* pResp = &pMsgIn->stunRespMessage; StopTimer(trans, STUN_SIGNAL_TimerRetransmit); - trans->ttl = pMsgIn->ttl; + trans->stunBindReq.ttl = pMsgIn->ttl; if ( StoreBindResp(trans, pResp) ) { BindRespCallback(trans, (struct sockaddr*)&pMsgIn->srcAddr); @@ -1479,8 +1274,8 @@ StunState_WaitBindResp(STUN_TRANSACTION_DATA* trans, case STUN_SIGNAL_ICMPResp: { StunRespStruct* pMsgIn = (StunRespStruct*)payload; - trans->ICMPtype = pMsgIn->ICMPtype; - trans->ttl = pMsgIn->ttl; + trans->ICMPtype = pMsgIn->ICMPtype; + trans->stunBindReq.ttl = pMsgIn->ttl; ICMPRespCallback(trans, (struct sockaddr*)&pMsgIn->srcAddr); trans->stats.ICMPReceived++; SetNextState(trans, STUN_STATE_Idle); @@ -1543,7 +1338,7 @@ StunState_Cancelled(STUN_TRANSACTION_DATA* trans, StunMessage* pResp = &pMsgIn->stunRespMessage; StopTimer(trans, STUN_SIGNAL_TimerRetransmit); - trans->ttl = pMsgIn->ttl; + trans->stunBindReq.ttl = pMsgIn->ttl; if ( StoreBindResp(trans, pResp) ) { BindRespCallback(trans, (struct sockaddr*)&pMsgIn->srcAddr); @@ -1597,7 +1392,7 @@ StunClient_clearStats(STUN_CLIENT_DATA* clientData) return; } - memset(&clientData->stats, 0, sizeof clientData->stats); + memset(&clientData->stats, 0, sizeof clientData->stats); for (int i = 0; i < MAX_STUN_TRANSACTIONS; i++) { @@ -1615,7 +1410,7 @@ StunClient_dumpStats (STUN_CLIENT_DATA* clientData, struct StunClientStats* ptr = &clientData->stats; int usedCnt = 0; - memset(&stats, 0, sizeof stats); + memset(&stats, 0, sizeof stats); stats.InProgress += ptr->InProgress; stats.BindReqSent += ptr->BindReqSent; diff --git a/src/stunlib.c b/src/stunlib.c index 7bcda96..2b6454a 100644 --- a/src/stunlib.c +++ b/src/stunlib.c @@ -10,6 +10,7 @@ # define SHA1 CC_SHA1 #else +#include #include #include #include @@ -284,10 +285,10 @@ dumpbuff(char* s, uint32_t len) { uint32_t i; - printError("%s\n", s); + printError("%s\n", s); for (i = 0; i < len; i++) { - printError("%02x,", buf[i]); + printError("%02x,", buf[i]); if (i % 10 == 0) { printError("\n"); @@ -732,11 +733,11 @@ stunEncodeUnknownAtr(StunAtrUnknown* pUnk, { return false; } - write_16( pBuf, STUN_ATTR_UnknownAttribute); - write_16( pBuf, ( (pUnk->numAttributes) * 2 ) ); + write_16( pBuf, STUN_ATTR_UnknownAttribute); + write_16( pBuf, ( (pUnk->numAttributes) * 2 ) ); for (i = 0; i < pUnk->numAttributes; i++) { - write_16( pBuf, pUnk->attrType[i]); + write_16(pBuf, pUnk->attrType[i]); } if (rest) { @@ -911,6 +912,25 @@ stunEncodeNetworkStatus(StunAtrNetworkStatus* pNetworkStatus, return true; } +static bool +stunEncodeTransCount(StunAtrTransCount* pTransCount, + uint8_t** pBuf, + int* nBufLen) +{ + if (*nBufLen < 24) + { + return false; + } + write_16(pBuf, STUN_ATTR_TransCount); /* Attr type */ + write_16(pBuf, 4); /* Length */ + write_16(pBuf, pTransCount->reserved); + write_8(pBuf, pTransCount->reqCnt); + write_8(pBuf, pTransCount->respCnt); + + *nBufLen -= 8; + return true; +} + static bool stunEncodeTTL(StunAtrTTL* pTTL, uint8_t** pBuf, @@ -981,7 +1001,7 @@ stunlib_EncodeIndication(uint8_t msgType, int length = 0; memset( &stunMsg, 0, sizeof(StunMessage) ); - stunlib_createId(&stunMsg.msgHdr.id, rand(), 0); + stunlib_createId(&stunMsg.msgHdr.id); if (dstAddr->sa_family == AF_INET) { @@ -1011,7 +1031,7 @@ stunlib_EncodeIndication(uint8_t msgType, /* STD TURN: sendInd(XorPeerAddr, Data) no integrity */ stunMsg.msgHdr.msgType = msgType; stunMsg.xorPeerAddrEntries = 1; - memcpy( &stunMsg.xorPeerAddress[0], &activeDstAddr, sizeof(StunIPAddress) ); + memcpy( &stunMsg.xorPeerAddress[0], &activeDstAddr, sizeof(StunIPAddress) ); stunMsg.hasData = true; stunMsg.data.dataLen = payloadLength; stunMsg.data.pData = dataBuf; /*The data (RTP packet) follows @@ -1251,7 +1271,7 @@ stunDecodeIPAddrAtr(StunIPAddress* pAddr, return false; } - read_16(pBuf, &flagtype); + read_16(pBuf, &flagtype); pAddr->familyType = (flagtype & 0xff); if (pAddr->familyType == STUN_ADDR_IPv4Family) @@ -1500,7 +1520,7 @@ stunDecodeStreamType(StunAtrStreamType* streamTypeAtr, - read_16(pBuf, &streamTypeAtr->type); + read_16(pBuf, &streamTypeAtr->type); read_8(pBuf, &streamTypeAtr->interactivity); read_8(pBuf, &streamTypeAtr->pad); *nBufLen -= 4; @@ -1528,6 +1548,25 @@ stunDecodeNetworkStatus(StunAtrNetworkStatus* networkStatusAtr, return true; } +static bool +stunDecodeTransCount(StunAtrTransCount* transCountAtr, + const uint8_t** pBuf, + int* nBufLen) +{ + if (*nBufLen < 4) + { + return false; + } + read_16(pBuf, &transCountAtr->reserved); + read_8(pBuf, &transCountAtr->reqCnt); + read_8(pBuf, &transCountAtr->respCnt); + + *nBufLen -= 4; + return true; +} + + + static bool stunDecodeCiscoNetworkFeedback(StunAtrCiscoNetworkFeedback* ciscoNetFeed, const uint8_t** pBuf, @@ -1589,7 +1628,7 @@ stun_printIP4Address(FILE* stream, char const* szHead, const StunAddress4* pAdr) { - printError(stream, " %s \t= {%d.%d.%d.%d:%d}\n", szHead, + printError(stream, " %s \t= {%d.%d.%d.%d:%d}\n", szHead, pAdr->addr >> 24 & 0xff, pAdr->addr >> 16 & 0xff, pAdr->addr >> 8 & 0xff, @@ -1709,7 +1748,7 @@ stun_printErrorCode(FILE* stream, char buf[1512]; memcpy(buf, pErr->reason, pErr->sizeReason); buf[pErr->sizeReason] = '\0'; - printError(stream, " error = {%d %d, \"%s\"[%d]}\n", + printError(stream, " error = {%d %d, \"%s\"[%d]}\n", pErr->errorClass, pErr->number, buf, pErr->sizeReason); } @@ -1718,7 +1757,7 @@ stun_printUnknown(FILE* stream, const StunAtrUnknown* pUnk) { int i; - printError(stream, " unknownAttribute = [%d]{", pUnk->numAttributes); + printError(stream, " unknownAttribute = [%d]{", pUnk->numAttributes); for (i = 0; i < pUnk->numAttributes; i++) { printError(stream, @@ -1726,7 +1765,7 @@ stun_printUnknown(FILE* stream, (i ? ',' : ' '), pUnk->attrType[i]); } - printError(stream, "\n"); + printError(stream, "\n"); } @@ -1739,7 +1778,7 @@ stun_printData(FILE* stream, { return; } - printError(stream, + printError(stream, " %s \t= %p (%d)\n", szHead, pData->pData, @@ -1769,10 +1808,10 @@ stun_printMessage(FILE* stream, printError(stream, "NULL\n"); return; } - printError(stream, "{\n"); - printError(stream, " msgHdr.type \t= %d\n", pMsg->msgHdr.msgType); - printError(stream, " msgHdr.length \t= %d\n", pMsg->msgHdr.msgLength); - printError(stream, " msgHdr.id[] \t = "); + printError(stream, "{\n"); + printError(stream, " msgHdr.type \t= %d\n", pMsg->msgHdr.msgType); + printError(stream, " msgHdr.length \t= %d\n", pMsg->msgHdr.msgLength); + printError(stream, " msgHdr.id[] \t = "); stun_printTransId(stream, &pMsg->msgHdr.id); printError(stream, "\n"); @@ -1841,7 +1880,7 @@ stun_printMessage(FILE* stream, if (message->hasAlternateServer) { - stun_printIPAddress(stream, "alternateServer", &message->alternateServer); + stun_printIPAddress(stream, "alternateServer", &message->alternateServer); } if (message->xorPeerAddrEntries) @@ -1896,18 +1935,18 @@ stun_printMessage(FILE* stream, if (message->hasMessageIntegrity) { - printError(stream, + printError(stream, " integrity.offset = %02u", message->messageIntegrity.offset); - printError(stream, " integrity.hash[] = "); + printError(stream, " integrity.hash[] = "); for (i = 0; i < 20; i++) { printError(stream, "%02x ", message->messageIntegrity.hash[i]); } - printError(stream, "\n"); + printError(stream, "\n"); } - printError(stream, "}\n"); + printError(stream, "}\n"); } void @@ -1919,7 +1958,7 @@ stunlib_printBuffer(FILE* stream, int i; int linecnt = 0; - printError(stream, "%s Buffer (%i) = [\n", szHead, len); + printError(stream, "%s Buffer (%i) = [\n", szHead, len); for (i = 0; i < len; i++, linecnt++) { if (linecnt == 4) @@ -1930,11 +1969,11 @@ stunlib_printBuffer(FILE* stream, } else { - printError( stream, "%c", (linecnt ? ',' : ' ') ); + printError( stream, "%c", (linecnt ? ',' : ' ') ); } - printError( stream, " %02x", (uint8_t)( *( (pBuf + i) ) ) ); + printError( stream, " %02x", (uint8_t)( *( (pBuf + i) ) ) ); } - printError( stream, "];\n"); + printError(stream, "];\n"); } char const* @@ -2093,7 +2132,7 @@ stunlib_DecodeMessage(const uint8_t* buf, } if (restlen < message->msgHdr.msgLength) { - printError(stream, + printError(stream, "stunlib_DecodeMessage: The length in msg (%d) is larger than rest of buffer (%d)!\n", message->msgHdr.msgLength, restlen); @@ -2104,7 +2143,7 @@ stunlib_DecodeMessage(const uint8_t* buf, { if (stream) { - printError(stream, + printError(stream, "Parsing attribute head with restlen=%d at %p\n", restlen, pCurrPtr); @@ -2121,7 +2160,7 @@ stunlib_DecodeMessage(const uint8_t* buf, } if (stream) { - printError(stream, + printError(stream, "Attribute Header parsed: type == %d, length == %d\n", sAtr.type, sAtr.length); @@ -2407,6 +2446,17 @@ stunlib_DecodeMessage(const uint8_t* buf, message->hasBandwidthUsage = true; break; + case STUN_ATTR_TransCount: + if ( !stunDecodeTransCount(&message->transCount, + &pCurrPtr, + &restlen) ) + { + return false; + } + message->hasTransCount = true; + break; + + case STUN_ATTR_NetworkStatus: if (message->hasMessageIntegrity) { @@ -2504,7 +2554,9 @@ stunlib_DecodeMessage(const uint8_t* buf, { if (stream) { - fprintf(stream, " Message length or attribute length error.\n"); + fprintf(stream, + " Message length or attribute length error(%i).\n", + restlen); } return false; } @@ -2669,7 +2721,7 @@ stunlib_encodeStunKeepAliveResp(StunMsgId* transId, { StunMsgHdr h; - memcpy( &h.id, transId, sizeof(h.id) ); + memcpy( &h.id, transId, sizeof(h.id) ); h.msgType = STUN_MSG_BindResponseMsg; h.msgLength = (srvrRflxAddr->familyType == STUN_ADDR_IPv4Family) ? 12 : 24; @@ -2729,7 +2781,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, + printError(stream, "invalid arguments (%p, %p, %d)\n", message, buf, @@ -2749,7 +2801,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "Invalid Software (Name)\n"); + printError(stream, "Invalid Software (Name)\n"); } return 0; } @@ -2761,7 +2813,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "Invalid Priority attribute\n"); + printError(stream, "Invalid Priority attribute\n"); } return 0; } @@ -2773,7 +2825,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "Invalid ICEControlled\n"); + printError(stream, "Invalid ICEControlled\n"); } return 0; } @@ -2785,7 +2837,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "Invalid Username\n"); + printError(stream, "Invalid Username\n"); } return 0; } @@ -2797,7 +2849,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "Invalid Nonce attribute\n"); + printError(stream, "Invalid Nonce attribute\n"); } return 0; } @@ -2810,7 +2862,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "Invalid Realm attribute\n"); + printError(stream, "Invalid Realm attribute\n"); } return 0; } @@ -2822,7 +2874,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "Invalid Lifetime attribute\n"); + printError(stream, "Invalid Lifetime attribute\n"); } return 0; } @@ -2834,7 +2886,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "Invalid RequestedTransport attribute\n"); + printError(stream, "Invalid RequestedTransport attribute\n"); } return 0; } @@ -2848,7 +2900,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "Invalid RequestedAddressFamily attribute\n"); + printError(stream, "Invalid RequestedAddressFamily attribute\n"); } return 0; } @@ -2862,7 +2914,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "Invalid RequestedAddressFamily attribute\n"); + printError(stream, "Invalid RequestedAddressFamily attribute\n"); } return 0; } @@ -2875,7 +2927,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "Invalid IceControlling\n"); + printError(stream, "Invalid IceControlling\n"); } return 0; } @@ -2888,7 +2940,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "mappedAddress failed \n"); + printError(stream, "mappedAddress failed \n"); } return 0; } @@ -2899,7 +2951,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "Invalid Error attribute\n"); + printError(stream, "Invalid Error attribute\n"); } return 0; } @@ -2910,7 +2962,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "Invalid unknown attribute\n"); + printError(stream, "Invalid unknown attribute\n"); } return 0; } @@ -2925,7 +2977,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "Invalid xorMappedAddress\n"); + printError(stream, "Invalid xorMappedAddress\n"); } return 0; } @@ -2937,7 +2989,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "Invalid ChannelNumber attribute\n"); + printError(stream, "Invalid ChannelNumber attribute\n"); } return 0; } @@ -2951,7 +3003,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "Invalid Alternate Server\n"); + printError(stream, "Invalid Alternate Server\n"); } return 0; } @@ -2981,7 +3033,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "xorRelayAddressIPv4 failed \n"); + printError(stream, "xorRelayAddressIPv4 failed \n"); } return 0; } @@ -2996,7 +3048,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "xorRelayAddressIPv6 failed \n"); + printError(stream, "xorRelayAddressIPv6 failed \n"); } return 0; } @@ -3007,7 +3059,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "Invalid UseCandidate\n"); + printError(stream, "Invalid UseCandidate\n"); } return 0; } @@ -3018,7 +3070,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "Invalid DontFragment\n"); + printError(stream, "Invalid DontFragment\n"); } return 0; } @@ -3029,7 +3081,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "Invalid EvenPort attribute\n"); + printError(stream, "Invalid EvenPort attribute\n"); } return 0; } @@ -3042,7 +3094,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "Invalid Reservation Token attribute\n"); + printError(stream, "Invalid Reservation Token attribute\n"); } return 0; } @@ -3054,7 +3106,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "Invalid StreamType attribute\n"); + printError(stream, "Invalid StreamType attribute\n"); } return 0; } @@ -3067,7 +3119,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "Invalid BandwidthUsage attribute\n"); + printError(stream, "Invalid BandwidthUsage attribute\n"); } return 0; } @@ -3079,7 +3131,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "Invalid TTL attribute\n"); + printError(stream, "Invalid TTL attribute\n"); } return 0; } @@ -3091,7 +3143,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "Invalid Network Status attribute\n"); + printError(stream, "Invalid Network Status attribute\n"); } return 0; } @@ -3103,11 +3155,22 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "Invalid Cisco Network Feedback attribute\n"); + printError(stream, "Invalid Cisco Network Feedback attribute\n"); } return 0; } + if ( message->hasTransCount && + !stunEncodeTransCount(&message->transCount, + &pCurrPtr, + &restlen) ) + { + if (stream) + { + printError(stream, "Invalid TransCount attribute\n"); + } + return 0; + } /* note: DATA should be the last attribute */ if ( message->hasData && !stunEncodeDataAtr(&message->data, @@ -3116,7 +3179,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "Invalid Data attribute\n"); + printError(stream, "Invalid Data attribute\n"); } return 0; } @@ -3150,7 +3213,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "Invalid Network Status attribute\n"); + printError(stream, "Invalid Network Status attribute\n"); } return 0; } @@ -3162,7 +3225,7 @@ stunlib_encodeMessage(StunMessage* message, { if (stream) { - printError(stream, "Invalid Cisco Network Feedback attribute\n"); + printError(stream, "Invalid Cisco Network Feedback attribute\n"); } return 0; } @@ -3236,7 +3299,7 @@ stunlib_encodeMessage(StunMessage* message, } if (stream) { - printError(stream, "STUN_encode, messages to encode: \n"); + printError(stream, "STUN_encode, messages to encode: \n"); stun_printMessage(stream, message); printError(stream, "STUN_encode, buffer encoded: \n"); stunlib_printBuffer(stream, (uint8_t*)buf, msglen, "STUN"); @@ -3388,21 +3451,21 @@ stunlib_addChannelNumber(StunMessage* stunMsg, return true; } +/* transaction id compare */ +bool +stunlib_transIdIsEqual(const StunMsgId* a, + const StunMsgId* b) +{ + return (memcmp(a, b, STUN_MSG_ID_SIZE) == 0); +} /***** * Create our magic id.... *********/ void -stunlib_createId(StunMsgId* pId, - long randval, - unsigned char retries) +stunlib_createId(StunMsgId* pId) { - char xorval[16] = "cafeogslikt"; - uint8_t* pIdBuf = pId->octet; - write_32(&pIdBuf, randval); - write_16(&pIdBuf, retries); - write_16(&pIdBuf, 0); - write_32_xor(&pIdBuf, randval, (uint8_t*)xorval); + arc4random_buf(pId, STUN_MSG_ID_SIZE); } @@ -3445,12 +3508,10 @@ bool stunlib_checkFingerPrint(const uint8_t* buf, uint32_t fpOffset) { - uint32_t crc = stunlib_calculateFingerprint(buf, fpOffset - 4); uint32_t val; const uint8_t* pos = buf + fpOffset; read_32(&pos, &val); - if (crc == val) { return true; diff --git a/src/stunserver.c b/src/stunserver.c new file mode 100644 index 0000000..f92c3f6 --- /dev/null +++ b/src/stunserver.c @@ -0,0 +1,290 @@ + +#include +#include + +#include "stunserver.h" + + + +bool +CreateConnectivityBindingResp(StunMessage* stunMsg, + StunMsgId transactionId, + const struct sockaddr* mappedSockAddr, + uint8_t reqTrnspCnt, + uint8_t respTrnspCnt, + uint16_t response, + uint32_t responseCode, + DiscussData* discussData) +{ + StunIPAddress mappedAddr; + + if ( !sockaddr_isSet(mappedSockAddr) ) + { + return false; + } + + memset(stunMsg, 0, sizeof *stunMsg); + stunMsg->msgHdr.msgType = response; + + if (reqTrnspCnt != 0) + { + stunMsg->hasTransCount = true; + stunMsg->transCount.respCnt = respTrnspCnt; + stunMsg->transCount.reqCnt = reqTrnspCnt; + } + + if (mappedSockAddr->sa_family == AF_INET) + { + mappedAddr.familyType = STUN_ADDR_IPv4Family; + mappedAddr.addr.v4.port = ntohs( + ( (struct sockaddr_in*)mappedSockAddr )->sin_port); + mappedAddr.addr.v4.addr = ntohl( + ( (struct sockaddr_in*)mappedSockAddr )->sin_addr.s_addr); + + } + else if (mappedSockAddr->sa_family == AF_INET6) + { + mappedAddr.familyType = STUN_ADDR_IPv6Family; + mappedAddr.addr.v6.port = ntohs( + ( (struct sockaddr_in6*)mappedSockAddr )->sin6_port); + + /*TODO: will this be correct ? */ + memcpy( mappedAddr.addr.v6.addr, + ( (struct sockaddr_in6*)mappedSockAddr )->sin6_addr.s6_addr, + sizeof(mappedAddr.addr.v6.addr) ); + } + else + { + return false; + } + + /*id*/ + stunMsg->msgHdr.id = transactionId; + + /* The XOR address MUST be added according to the RFC */ + stunMsg->hasXorMappedAddress = true; + stunMsg->xorMappedAddress = mappedAddr; + + if (discussData != NULL) + { + stunMsg->hasStreamType = true; + stunMsg->streamType.type = discussData->streamType; + stunMsg->streamType.interactivity = discussData->interactivity; + + stunMsg->hasNetworkStatus = true; + stunMsg->networkStatus.flags = 0; + stunMsg->networkStatus.nodeCnt = 0; + stunMsg->networkStatus.upMaxBandwidth = 0; + stunMsg->networkStatus.downMaxBandwidth = 0; + + stunMsg->hasNetworkStatusResp = true; + stunMsg->networkStatusResp.flags = + discussData->networkStatusResp_flags; + stunMsg->networkStatusResp.nodeCnt = + discussData->networkStatusResp_nodeCnt; + stunMsg->networkStatusResp.upMaxBandwidth = + discussData->networkStatusResp_upMaxBandwidth; + stunMsg->networkStatusResp.downMaxBandwidth = + discussData->networkStatusResp_downMaxBandwidth; + } + if (responseCode != 200) + { + stunMsg->hasErrorCode = true; + stunMsg->errorCode.errorClass = responseCode / 100; + stunMsg->errorCode.number = (uint8_t) (responseCode % 100); + if (responseCode == 487) + { + strncpy( stunMsg->errorCode.reason, "Role Conflict", + sizeof (stunMsg->errorCode.reason) ); + stunMsg->errorCode.sizeReason = strlen(stunMsg->errorCode.reason); + } + else if (responseCode == 400) + { + strncpy( stunMsg->errorCode.reason, "Bad Request", + sizeof (stunMsg->errorCode.reason) ); + stunMsg->errorCode.sizeReason = strlen(stunMsg->errorCode.reason); + } + } + + return true; +} + + +static bool +SendConnectivityBindResponse(STUN_CLIENT_DATA* clientData, + int32_t globalSocketId, + StunMessage* stunRespMsg, + const char* password, + const struct sockaddr* dstAddr, + void* userData, + STUN_SENDFUNC sendFunc, + int proto, + bool useRelay) +{ + uint8_t stunBuff[STUN_MAX_PACKET_SIZE]; + int stunLen; + + (void) userData; + /* encode bind Response */ + stunLen = stunlib_encodeMessage(stunRespMsg, + (uint8_t*)stunBuff, + STUN_MAX_PACKET_SIZE, + (unsigned char*)password, /* md5key + **/ + password ? strlen(password) : 0, /* keyLen + **/ + NULL); + if (!stunLen) + { + StunPrint(clientData->logUserData, + clientData->Log_cb, + StunInfoCategory_Error, + " Failed to encode Binding request response\n"); + return false; + } + + /* send */ + /* sendFunc(globalSocketId, stunBuff, stunLen, dstAddr, useRelay, 0); */ + sendFunc(clientData->userCtx, + globalSocketId, + stunBuff, + stunLen, + dstAddr, + proto, + useRelay, + 0); + clientData->stats.BindRespSent++; + return true; +} + + +/********* Server handling of STUN BIND RESP *************/ +bool +StunServer_SendConnectivityBindingResp(STUN_CLIENT_DATA* clientData, + int32_t globalSocketId, + StunMsgId transactionId, + const char* password, + const struct sockaddr* mappedAddr, + const struct sockaddr* dstAddr, + uint8_t reqTrnspCnt, + uint8_t respTrnspCnt, + void* userData, + STUN_SENDFUNC sendFunc, + int proto, + bool useRelay, + uint32_t responseCode, + DiscussData* discussData) +{ + StunMessage stunRespMsg; + + /* format */ + if ( CreateConnectivityBindingResp(&stunRespMsg, + transactionId, + mappedAddr, + reqTrnspCnt, + respTrnspCnt, + (responseCode == + 200) ? STUN_MSG_BindResponseMsg : + STUN_MSG_BindErrorResponseMsg, + responseCode, + discussData) ) + { + /* encode and send */ + if ( SendConnectivityBindResponse(clientData, + globalSocketId, + &stunRespMsg, + password, + dstAddr, + userData, + sendFunc, + proto, + useRelay) ) + { + return true; + } + } + return false; +} + + +/********** Server handling of incoming STUN BIND REQ **********/ +bool +StunServer_HandleStunIncomingBindReqMsg(STUN_CLIENT_DATA* clientData, + STUN_INCOMING_REQ_DATA* pReq, + const StunMessage* stunMsg, + bool fromRelay) +{ + if (!clientData) + { + return false; + } + + memcpy( &pReq->transactionId, &stunMsg->msgHdr.id, sizeof(StunMsgId) ); + + pReq->fromRelay = fromRelay; + + if (stunMsg->hasUsername) + { + strncpy( pReq->ufrag, stunMsg->username.value, + min(stunMsg->username.sizeValue, STUN_MAX_STRING) ); + if (stunMsg->username.sizeValue < STUN_MAX_STRING) + { + pReq->ufrag[stunMsg->username.sizeValue] = '\0'; + } + else + { + pReq->ufrag[STUN_MAX_STRING - 1] = '\0'; + } + } + else + { + StunPrint(clientData->logUserData, + clientData->Log_cb, + StunInfoCategory_Error, + " Missing Username in Binding Request\n"); + return false; + } + + if (stunMsg->hasPriority) + { + pReq->peerPriority = stunMsg->priority.value; + } + else + { + StunPrint(clientData->logUserData, + clientData->Log_cb, + StunInfoCategory_Error, + " Missing Priority in Binding Request\n"); + return false; + } + + pReq->useCandidate = stunMsg->hasUseCandidate; + + if (stunMsg->hasControlling) + { + pReq->iceControlling = true; + pReq->tieBreaker = stunMsg->controlling.value; + } + else + { + pReq->iceControlling = false; + } + + if (stunMsg->hasControlled) + { + pReq->iceControlled = true; + pReq->tieBreaker = stunMsg->controlled.value; + } + else + { + pReq->iceControlled = false; + } + + if (fromRelay) + { + clientData->stats.BindReqReceived_ViaRelay++; + } + clientData->stats.BindReqReceived++; + + return true; +} diff --git a/src/stuntrace.c b/src/stuntrace.c index 9f76650..45ccadc 100644 --- a/src/stuntrace.c +++ b/src/stuntrace.c @@ -124,8 +124,7 @@ handleStunNoAnswer(struct hiutResult* result) result->remoteAlive = false; result->currentTTL = 1; - stunlib_createId(&result->currStunMsgId, - rand(), result->currentTTL); + stunlib_createId(&result->currStunMsgId); StunClient_startSTUNTrace( (STUN_CLIENT_DATA*)result->stunCtx, result, @@ -174,8 +173,8 @@ handleStunNoAnswer(struct hiutResult* result) { result->currentTTL++; } - stunlib_createId(&result->currStunMsgId, - rand(), result->currentTTL); + stunlib_createId(&result->currStunMsgId); + StunClient_startSTUNTrace( (STUN_CLIENT_DATA*)result->stunCtx, result, (struct sockaddr*)&result->remoteAddr, @@ -207,8 +206,7 @@ handleStunRespIcmp(struct hiutResult* result, result->remoteAlive = true; result->currentTTL = 1; - stunlib_createId(&result->currStunMsgId, - rand(), result->currentTTL); + stunlib_createId(&result->currStunMsgId); StunClient_startSTUNTrace( (STUN_CLIENT_DATA*)result->stunCtx, result, @@ -245,8 +243,7 @@ handleStunRespIcmp(struct hiutResult* result, false, false); - stunlib_createId(&result->currStunMsgId, - rand(), result->currentTTL); + stunlib_createId(&result->currStunMsgId); StunClient_startSTUNTrace( (STUN_CLIENT_DATA*)result->stunCtx, result, @@ -312,8 +309,7 @@ handleStunRespSucsessfull(struct hiutResult* result, result->remoteAlive = true; result->currentTTL = 1; - stunlib_createId(&result->currStunMsgId, - rand(), result->currentTTL); + stunlib_createId(&result->currStunMsgId); StunClient_startSTUNTrace( (STUN_CLIENT_DATA*)result->stunCtx, result, @@ -359,7 +355,10 @@ StunStatusCallBack(void* userCtx, { struct hiutResult* result = (struct hiutResult*)userCtx; - result->pathElement[stunCbData->ttl].gotAnswer = true; + if (stunCbData->ttl <= MAX_TTL) + { + result->pathElement[stunCbData->ttl].gotAnswer = true; + } switch (stunCbData->stunResult) { @@ -408,13 +407,12 @@ StunTrace_startTrace(STUN_CLIENT_DATA* clientData, return 0; } struct hiutResult* result; - uint32_t len; result = &clientData->traceResult; result->currentTTL = MAX_TTL; result->userCtx = userCtx; - stunlib_createId(&result->currStunMsgId, rand(), 1); + stunlib_createId(&result->currStunMsgId); result->stunCtx = clientData; /* Fill inn the hiut struct so we get something back in the CB */ /* TODO: Fix the struct so we do not store information twice!! */ @@ -437,21 +435,19 @@ StunTrace_startTrace(STUN_CLIENT_DATA* clientData, strncpy(result->username, ufrag, sizeof(result->username) - 1); strncpy(result->password, password, sizeof(result->password) - 1); - len = StunClient_startSTUNTrace(result->stunCtx, - result, - toAddr, - fromAddr, - false, - result->username, - result->password, - result->currentTTL, - result->currStunMsgId, - result->sockfd, - result->sendFunc, - StunStatusCallBack, - NULL); - result->stunLen = len; - - return len; + StunClient_startSTUNTrace(result->stunCtx, + result, + toAddr, + fromAddr, + false, + result->username, + result->password, + result->currentTTL, + result->currStunMsgId, + result->sockfd, + result->sendFunc, + StunStatusCallBack, + NULL); + return 1; } diff --git a/src/turnclient.c b/src/turnclient.c index 668ca25..f2f989f 100644 --- a/src/turnclient.c +++ b/src/turnclient.c @@ -219,13 +219,6 @@ TurnTransactionIdString(char* dst, } } -static int -TurnRand(void) -{ - return rand(); -} - - static int getAddrFamily(const TURN_INSTANCE_DATA* pInst) { @@ -399,7 +392,7 @@ ChannelBindReqParamsOk(TURN_INSTANCE_DATA* pInst, if ( !IsValidBindChannelNumber(channelNumber) ) /* channel number ignored if * creating a permission */ { - TurnPrint(pInst, + TurnPrint(pInst, TurnInfoCategory_Error, " ChannelBindReq - illegal channel number %0X ", pInst->id, @@ -409,7 +402,7 @@ ChannelBindReqParamsOk(TURN_INSTANCE_DATA* pInst, if ( !sockaddr_isSet(peerTrnspAddr) ) { - TurnPrint(pInst, + TurnPrint(pInst, TurnInfoCategory_Error, " ChannelBindReq - illegal peerTRansport Address ", pInst->id); @@ -643,25 +636,25 @@ TurnClientGetStats(const TURN_INSTANCE_DATA* pInst, { if (pInst->state >= TURN_STATE_Allocated) { - sockaddr_copy( (struct sockaddr*)&Stats->AllocResp.srflxAddr, + sockaddr_copy( (struct sockaddr*)&Stats->AllocResp.srflxAddr, (struct sockaddr*)&pInst->srflxAddr ); - sockaddr_copy( (struct sockaddr*)&Stats->AllocResp.relAddrIPv4, + sockaddr_copy( (struct sockaddr*)&Stats->AllocResp.relAddrIPv4, (struct sockaddr*)&pInst->relAddr_IPv4 ); - sockaddr_copy( (struct sockaddr*)&Stats->AllocResp.relAddrIPv6, + sockaddr_copy( (struct sockaddr*)&Stats->AllocResp.relAddrIPv6, (struct sockaddr*)&pInst->relAddr_IPv6 ); Stats->channelBound = pInst->channelBound; if (pInst->channelBound) { Stats->channelNumber = pInst->channelBindInfo.channelNumber; - sockaddr_copy( (struct sockaddr*)&Stats->BoundPeerTrnspAddr, + sockaddr_copy( (struct sockaddr*)&Stats->BoundPeerTrnspAddr, (struct sockaddr*)&pInst->channelBindInfo.peerTrnspAddr ); /* a bound channel also creates a permission, so show this */ Stats->permissionsInstalled = 1; Stats->numberOfPeers = 1; - sockaddr_copy( (struct sockaddr*)&Stats->PermPeerTrnspAddr[0], + sockaddr_copy( (struct sockaddr*)&Stats->PermPeerTrnspAddr[0], (struct sockaddr*)&pInst->channelBindInfo.peerTrnspAddr ); } else @@ -786,7 +779,7 @@ TurnResultToStr(TurnResult_T res) static void StopAllTimers(TURN_INSTANCE_DATA* pInst) { - TurnPrint(pInst, + TurnPrint(pInst, TurnInfoCategory_Trace, " StopAllTimers", pInst->id); @@ -884,7 +877,7 @@ StartTimer(TURN_INSTANCE_DATA* pInst, TURN_SIGNAL sig, uint32_t durationMsec) { - TurnPrint(pInst, + TurnPrint(pInst, TurnInfoCategory_Trace, " StartTimer(%s, %dms)", pInst->id, @@ -924,7 +917,7 @@ static void StopTimer(TURN_INSTANCE_DATA* pInst, TURN_SIGNAL sig) { - TurnPrint( pInst, TurnInfoCategory_Trace, " StopTimer(%s)", + TurnPrint( pInst, TurnInfoCategory_Trace, " StopTimer(%s)", pInst->id, TurnsigToStr(sig) ); switch (sig) @@ -975,13 +968,13 @@ StoreAllocateReq(TURN_INSTANCE_DATA* pInst, TurnAllocateReqStuct* pMsgIn) { /* copy whole msg */ - memcpy( &pInst->turnAllocateReq, pMsgIn, + memcpy( &pInst->turnAllocateReq, pMsgIn, sizeof(TurnAllocateReqStuct) ); /* copy crendentials to seperate area */ - memcpy( pInst->userCredentials.stunUserName, pMsgIn->username, + memcpy( pInst->userCredentials.stunUserName, pMsgIn->username, sizeof(pInst->userCredentials.stunUserName) ); - memcpy( pInst->userCredentials.stunPassword, pMsgIn->password, + memcpy( pInst->userCredentials.stunPassword, pMsgIn->password, sizeof(pInst->userCredentials.stunPassword) ); } @@ -989,7 +982,7 @@ static void StoreChannelBindReq(TURN_INSTANCE_DATA* pInst, TurnChannelBindInfo_T* pMsgIn) { - memcpy( &pInst->channelBindInfo, pMsgIn, sizeof(pInst->channelBindInfo) ); + memcpy( &pInst->channelBindInfo, pMsgIn, sizeof(pInst->channelBindInfo) ); } static bool @@ -1002,7 +995,7 @@ static void StoreCreatePermReq(TURN_INSTANCE_DATA* pInst, TurnCreatePermissionInfo_T* pMsgIn) { - memcpy( &pInst->createPermInfo, pMsgIn, sizeof(pInst->createPermInfo) ); + memcpy( &pInst->createPermInfo, pMsgIn, sizeof(pInst->createPermInfo) ); } static bool @@ -1212,7 +1205,7 @@ StoreRelayAddressStd(TURN_INSTANCE_DATA* pInst, } else { - TurnPrint(pInst, + TurnPrint(pInst, TurnInfoCategory_Error, " Missing Xor RelayAddress AllocResp", pInst->id); @@ -1240,7 +1233,7 @@ StoreLifetime(TURN_INSTANCE_DATA* pInst, } else { - TurnPrint(pInst, + TurnPrint(pInst, TurnInfoCategory_Error, " Missing Lifetime in AllocResp", pInst->id); @@ -1271,11 +1264,9 @@ static void BuildInitialAllocateReq(TURN_INSTANCE_DATA* pInst, StunMessage* pReq) { - unsigned long rndval = TurnRand(); - memset( pReq, 0, sizeof(StunMessage) ); pReq->msgHdr.msgType = STUN_MSG_AllocateRequestMsg; - stunlib_createId(&pReq->msgHdr.id, rndval, 0); + stunlib_createId(&pReq->msgHdr.id); stunlib_addSoftware(pReq, pInst->softwareVersionStr, STUN_DFLT_PAD); stunlib_addRequestedTransport(pReq, STUN_REQ_TRANSPORT_UDP); @@ -1316,11 +1307,9 @@ static void BuildNewAllocateReq(TURN_INSTANCE_DATA* pInst, StunMessage* pReq) { - unsigned long rndval = TurnRand(); - memset( pReq, 0, sizeof(StunMessage) ); pReq->msgHdr.msgType = STUN_MSG_AllocateRequestMsg; - stunlib_createId(&pReq->msgHdr.id, rndval, 1); + stunlib_createId(&pReq->msgHdr.id); stunlib_addRealm(pReq, pInst->userCredentials.realm, STUN_DFLT_PAD); stunlib_addUserName(pReq, pInst->userCredentials.stunUserName, STUN_DFLT_PAD); stunlib_addNonce(pReq, pInst->userCredentials.nonce, STUN_DFLT_PAD); @@ -1363,10 +1352,8 @@ BuildRefreshAllocateReq(TURN_INSTANCE_DATA* pInst, StunMessage* pReq, uint32_t lifetimeSec) { - unsigned long rndval = TurnRand(); - memset( pReq, 0, sizeof(StunMessage) ); - stunlib_createId(&pReq->msgHdr.id, rndval, 1); + stunlib_createId(&pReq->msgHdr.id); pReq->hasLifetime = true; pReq->lifetime.value = lifetimeSec; @@ -1396,7 +1383,7 @@ BuildChannelBindReq(TURN_INSTANCE_DATA* pInst, memset( pReq, 0, sizeof(StunMessage) ); pReq->msgHdr.msgType = STUN_MSG_ChannelBindRequestMsg; - stunlib_createId(&pReq->msgHdr.id, TurnRand(), 0); + stunlib_createId(&pReq->msgHdr.id); if (peerAddr->sa_family == AF_INET) { @@ -1419,7 +1406,7 @@ BuildChannelBindReq(TURN_INSTANCE_DATA* pInst, } - memcpy( &pReq->xorPeerAddress[0], &peerTrnspAddr, sizeof(StunIPAddress) ); + memcpy( &pReq->xorPeerAddress[0], &peerTrnspAddr, sizeof(StunIPAddress) ); pReq->xorPeerAddrEntries = 1; /* Channel No */ @@ -1444,7 +1431,7 @@ BuildCreatePermReq(TURN_INSTANCE_DATA* pInst, memset( pReq, 0, sizeof(StunMessage) ); pReq->msgHdr.msgType = STUN_MSG_CreatePermissionRequestMsg; - stunlib_createId(&pReq->msgHdr.id, TurnRand(), 0); + stunlib_createId(&pReq->msgHdr.id); /* peer address(es) */ for (i = 0; i < pInst->createPermInfo.numberOfPeers; i++) @@ -1472,7 +1459,7 @@ BuildCreatePermReq(TURN_INSTANCE_DATA* pInst, } - memcpy( &pReq->xorPeerAddress[i], &peerTrnspAddr, sizeof(StunIPAddress) ); + memcpy( &pReq->xorPeerAddress[i], &peerTrnspAddr, sizeof(StunIPAddress) ); pReq->xorPeerAddrEntries++; } @@ -1548,7 +1535,7 @@ GetServerAddrFromAltServer(TURN_INSTANCE_DATA* pInst, } else { - TurnPrint(pInst, + TurnPrint(pInst, TurnInfoCategory_Error, " Missing Alternative Server in AllocRespErr", pInst->id); @@ -1590,7 +1577,7 @@ CheckRefreshRespError(TURN_INSTANCE_DATA* pInst, } else { - TurnPrint(pInst, + TurnPrint(pInst, TurnInfoCategory_Error, " No error code in RefreshRespError", pInst->id); @@ -1819,7 +1806,7 @@ RetransmitLastReq(TURN_INSTANCE_DATA* pInst) static void StartAllocRefreshTimer(TURN_INSTANCE_DATA* pInst) { - StartTimer(pInst, + StartTimer(pInst, TURN_SIGNAL_TimerRefreshAlloc, (pInst->lifetime / 2) * 1000); } @@ -1827,7 +1814,7 @@ StartAllocRefreshTimer(TURN_INSTANCE_DATA* pInst) static void StartChannelBindRefreshTimer(TURN_INSTANCE_DATA* pInst) { - StartTimer(pInst, + StartTimer(pInst, TURN_SIGNAL_TimerRefreshChannel, TURN_REFRESH_CHANNEL_TIMER_SEC * 1000); } @@ -1835,7 +1822,7 @@ StartChannelBindRefreshTimer(TURN_INSTANCE_DATA* pInst) static void StartCreatePermissionRefreshTimer(TURN_INSTANCE_DATA* pInst) { - StartTimer(pInst, + StartTimer(pInst, TURN_SIGNAL_TimerRefreshPermission, TURN_REFRESH_PERMISSION_TIMER_SEC * 1000); } @@ -1857,7 +1844,7 @@ static void StartFirstRetransmitTimer(TURN_INSTANCE_DATA* pInst) { pInst->retransmits = 0; - StartTimer(pInst, TURN_SIGNAL_TimerRetransmit, + StartTimer(pInst, TURN_SIGNAL_TimerRetransmit, stunTimeoutList[pInst->retransmits]); } @@ -1865,7 +1852,7 @@ StartFirstRetransmitTimer(TURN_INSTANCE_DATA* pInst) static void StartNextRetransmitTimer(TURN_INSTANCE_DATA* pInst) { - StartTimer(pInst, TURN_SIGNAL_TimerRetransmit, + StartTimer(pInst, TURN_SIGNAL_TimerRetransmit, stunTimeoutList[pInst->retransmits]); } @@ -1959,7 +1946,7 @@ TurnClientFsm(TURN_INSTANCE_DATA* pInst, } else if (sig == TURN_SIGNAL_DeAllocate) { - CallBack(pInst, TurnResult_RelayReleaseFailed); + CallBack(pInst, TurnResult_RelayReleaseFailed); } else { diff --git a/test/stunclient_test.c b/test/stunclient_test.c index 96bd530..04960d6 100644 --- a/test/stunclient_test.c +++ b/test/stunclient_test.c @@ -45,12 +45,14 @@ DiscussData discussData; char logStr[200]; +int lastReqCnt; +int lastTranspRespCnt; +int lastTranspReqCnt; +int lastRTT; + CTEST_DATA(data) { int a; - - - }; #define STUN_TICK_INTERVAL_MS 50 @@ -61,6 +63,9 @@ StunStatusCallBack(void* ctx, { (void)ctx; stunResult = retData->stunResult; + lastTranspRespCnt = retData->respTransCnt; + lastTranspReqCnt = retData->reqTransCnt; + lastRTT = retData->rtt; /* printf("Got STUN status callback\n");// (Result (%i)\n", * retData->stunResult); */ } @@ -102,6 +107,15 @@ SendRawStun(void* ctx, sockaddr_toString(addr, addr_str, SOCKADDR_MAX_STRLEN, true); + // And then we deencode to chek if correct values are set.. + StunMessage stunMsg; + stunlib_DecodeMessage(buf, len, &stunMsg, NULL, + NULL); + lastReqCnt = 0; + if(stunMsg.hasTransCount){ + lastReqCnt = stunMsg.transCount.reqCnt; + //lastTranspRespCnt = stunMsg.transCount.respCnt; + } /* printf("Sendto: '%s'\n", addr_str); */ } @@ -114,6 +128,7 @@ stundbg(void* ctx, (void) category; (void) ctx; strncpy(logStr, errStr, sizeof logStr); + //printf("%s\n", errStr); } static int @@ -225,7 +240,9 @@ SimBindSuccessResp(bool IPv6, m.xorMappedAddress.addr.v4.addr = test_addr_ipv4; m.xorMappedAddress.addr.v4.port = test_port_ipv4; } - + m.hasTransCount = true; + m.transCount.respCnt = 2; + m.transCount.reqCnt = lastReqCnt; StunClient_HandleIncResp(stunInstance, &m, NULL); } @@ -317,8 +334,8 @@ CTEST(stunclient, logger) { StunClient_Alloc(&stunInstance); StunClient_RegisterLogger(stunInstance, - stundbg, - NULL); + stundbg, + NULL); StartBindTransaction(0); ASSERT_TRUE( 0 == strncmp("", logStr, 15) ); @@ -360,6 +377,9 @@ CTEST(stunclient, WaitBindRespNotAut_Timeout) { ASSERT_TRUE(stunResult == StunResult_Empty); StunClient_Alloc(&stunInstance); + StunClient_RegisterLogger(stunInstance, + stundbg, + NULL); sockaddr_initFromString( (struct sockaddr*)&stunServerAddr, "193.200.93.152:3478" ); @@ -383,7 +403,7 @@ CTEST(stunclient, WaitBindRespNotAut_Timeout) { StunClient_HandleTick(stunInstance, STUN_TICK_INTERVAL_MS); } - + ASSERT_TRUE(lastReqCnt == 9); ASSERT_TRUE(stunResult == StunResult_BindFailNoAnswer); StunClient_free(stunInstance); } @@ -399,8 +419,38 @@ CTEST(stunclient, WaitBindRespNotAut_BindSuccess) /*Just quick sanity if NULL ihandled propperly */ StunClient_HandleIncResp(NULL, NULL, NULL); SimBindSuccessRespWrongId(runningAsIPv6, true); + SimBindSuccessResp(runningAsIPv6, true); + ASSERT_TRUE(lastReqCnt == 1); + ASSERT_TRUE(stunResult == StunResult_BindOk); + StunClient_free(stunInstance); +} + +CTEST(stunclient, BindReq_TranportCnt) +{ + StunClient_Alloc(&stunInstance); + sockaddr_initFromString( (struct sockaddr*)&stunServerAddr, + "193.200.93.152:3478" ); + + StartBindTransaction(0); + ASSERT_TRUE(lastReqCnt == 1); + for (int i = 0; i < 5; i++) + { + StunClient_HandleTick(stunInstance, STUN_TICK_INTERVAL_MS); + } + ASSERT_TRUE(lastReqCnt == 2); + + for (int i = 0; i < 5; i++) + { + StunClient_HandleTick(stunInstance, STUN_TICK_INTERVAL_MS); + } + ASSERT_TRUE(lastReqCnt == 3); + SimBindSuccessResp(runningAsIPv6, true); ASSERT_TRUE(stunResult == StunResult_BindOk); + + ASSERT_TRUE(lastRTT > 2); + ASSERT_TRUE(lastTranspReqCnt == 3); + ASSERT_TRUE(lastTranspRespCnt == 2); StunClient_free(stunInstance); } diff --git a/test/stunserver_test.c b/test/stunserver_test.c index fc7627c..abfa635 100644 --- a/test/stunserver_test.c +++ b/test/stunserver_test.c @@ -3,7 +3,7 @@ #include -#include "stunclient.h" +#include "stunserver.h" #include "sockaddr_util.h" #include "test_utils.h" @@ -20,12 +20,15 @@ static struct sockaddr_storage LastAddress; StunResult_T stunResult; struct sockaddr_storage stunServerAddr; +struct sockaddr_storage mappedAddr; DiscussData discussData; STUN_CLIENT_DATA* stunInstance; #define STUN_TICK_INTERVAL_MS 50 +const char passwd[] ="testtest"; + static void SendRawStun(void* ctx, int sockfd, @@ -55,6 +58,41 @@ SendRawStun(void* ctx, } + +CTEST(stunserver, Encode_decode) +{ + StunMessage stunMsg; + StunMessage stunResponse; + StunMsgId stunId; + + uint8_t stunBuff[STUN_MAX_PACKET_SIZE]; + stunlib_createId(&stunId); + + sockaddr_initFromString( (struct sockaddr*)&mappedAddr, + "193.200.93.152:3478" ); + CreateConnectivityBindingResp(&stunMsg, + stunId, + (struct sockaddr *)&mappedAddr, + 1, + 1, + STUN_MSG_BindResponseMsg, + 200, + NULL); + + int len = stunlib_encodeMessage(&stunMsg, + (uint8_t*)stunBuff, + STUN_MAX_PACKET_SIZE, + (unsigned char *) passwd, + strlen(passwd), + NULL); + ASSERT_TRUE(len == 72); + + ASSERT_TRUE( stunlib_DecodeMessage(stunBuff, len, + &stunResponse, + NULL, NULL /*stdout for debug*/)); + +} + CTEST(stunserver, HandleReq_Valid) { STUN_INCOMING_REQ_DATA pReq; @@ -126,6 +164,8 @@ CTEST(stunserver, SendResp_Valid) mappedAddr, (struct sockaddr*)& servAddr, + 0, + 0, NULL, SendRawStun, 0, @@ -142,6 +182,8 @@ CTEST(stunserver, SendResp_Valid) mappedAddr, (struct sockaddr*)& servAddr, + 2, + 3, NULL, SendRawStun, 0, @@ -170,6 +212,8 @@ CTEST(stunserver, SendResp_Valid_IPv6) mappedAddr, (struct sockaddr*)& servAddr, + 0, + 0, NULL, SendRawStun, 0, @@ -186,6 +230,8 @@ CTEST(stunserver, SendResp_Valid_IPv6) mappedAddr, (struct sockaddr*)& servAddr, + 0, + 0, NULL, SendRawStun, 0, @@ -221,6 +267,8 @@ CTEST(stunserver, SendDiscussResp_Valid) stunServerAddr, (struct sockaddr*)& stunServerAddr, + 2, + 2, NULL, SendRawStun, 0, diff --git a/test/stuntrace_test.c b/test/stuntrace_test.c index b22f446..6144b70 100644 --- a/test/stuntrace_test.c +++ b/test/stuntrace_test.c @@ -20,6 +20,19 @@ static const uint8_t StunCookie[] = STUN_MAGIC_COOKIE_ARRAY; const uint64_t test_addr_ipv4 = 1009527574; /* "60.44.43.22"); */ const uint32_t test_port_ipv4 = 43000; + +void +stundbg(void* ctx, + StunInfoCategory_T category, + char* errStr) +{ + (void) category; + (void) ctx; + (void) errStr; +// strncpy(logStr, errStr, sizeof logStr); +// printf("%s\n", errStr); +} + static void sendPacket(void* ctx, int sockfd, @@ -537,8 +550,9 @@ CTEST(stuntrace, run_IPv4_Stunresp) "192.168.1.34:45674" ); StunClient_Alloc(&clientData); - - + StunClient_RegisterLogger(clientData, + stundbg, + NULL); int len = StunTrace_startTrace(clientData, &someData, (const struct sockaddr*)&remoteAddr, @@ -561,22 +575,20 @@ CTEST(stuntrace, run_IPv4_Stunresp) m.xorMappedAddress.familyType = STUN_ADDR_IPv4Family; m.xorMappedAddress.addr.v4.addr = test_addr_ipv4; m.xorMappedAddress.addr.v4.port = test_port_ipv4; - StunClient_HandleIncResp(clientData, &m, NULL); - /* First hop.. */ - ASSERT_TRUE(LastTTL == 1); + ASSERT_TRUE(LastTTL == 40); sockaddr_initFromString( (struct sockaddr*)&hop1Addr, "192.168.1.1:45674" ); - StunClient_HandleICMP(clientData, + StunClient_HandleICMP(clientData, (struct sockaddr*)&hop1Addr, 11); - ASSERT_TRUE( sockaddr_alike( (struct sockaddr*)&LastHopAddr, + ASSERT_FALSE( sockaddr_alike( (struct sockaddr*)&LastHopAddr, (struct sockaddr*)&hop1Addr ) ); - ASSERT_TRUE( LastTTL == 2); + ASSERT_TRUE( LastTTL == 40); sockaddr_initFromString( (struct sockaddr*)&hop2Addr, "193.200.93.152:45674" ); @@ -584,6 +596,8 @@ CTEST(stuntrace, run_IPv4_Stunresp) StunClient_HandleICMP(clientData, (struct sockaddr*)&hop2Addr, 3); + + ASSERT_TRUE( sockaddr_alike( (struct sockaddr*)&LastHopAddr, (struct sockaddr*)&hop2Addr ) ); ASSERT_TRUE( Done); @@ -711,7 +725,7 @@ CTEST(stuntrace, run_IPv4_Stunresp_end) NULL); /* First hop.. */ - ASSERT_TRUE(LastTTL == 1); + ASSERT_TRUE(LastTTL == 40); sockaddr_initFromString( (struct sockaddr*)&hop1Addr, "192.168.1.1:45674" ); StunClient_HandleICMP(clientData, @@ -720,7 +734,7 @@ CTEST(stuntrace, run_IPv4_Stunresp_end) ASSERT_TRUE( sockaddr_alike( (struct sockaddr*)&LastHopAddr, (struct sockaddr*)&hop1Addr ) ); - ASSERT_TRUE( LastTTL == 2); + ASSERT_TRUE( LastTTL == 40); memcpy(&m.msgHdr.id, &LastTransId, STUN_MSG_ID_SIZE); StunClient_HandleIncResp(clientData, @@ -783,7 +797,7 @@ CTEST(stuntrace, run_IPv4_Stunresp_max_ttl) } /* First hop.. */ - ASSERT_TRUE(LastTTL == 39); + ASSERT_TRUE(LastTTL == 40); sockaddr_initFromString( (struct sockaddr*)&hop1Addr, "192.168.1.1:45674" ); StunClient_HandleICMP(clientData,