stun.cc File Reference

#include <cassert>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include <net/if.h>
#include "stun_udp.h"
#include <time.h>

Go to the source code of this file.

Defines

#define NOSSL

Functions

static void computeHmac (char *hmac, const char *input, int length, const char *key, int keySize)
static bool stunParseAtrAddress (char *body, unsigned int hdrLen, StunAtrAddress4 &result)
static bool stunParseAtrChangeRequest (char *body, unsigned int hdrLen, StunAtrChangeRequest &result)
static bool stunParseAtrError (char *body, unsigned int hdrLen, StunAtrError &result)
static bool stunParseAtrUnknown (char *body, unsigned int hdrLen, StunAtrUnknown &result)
static bool stunParseAtrString (char *body, unsigned int hdrLen, StunAtrString &result)
static bool stunParseAtrIntegrity (char *body, unsigned int hdrLen, StunAtrIntegrity &result)
bool stunParseMessage (char *buf, unsigned int bufLen, StunMessage &msg, bool verbose)
static char * encode16 (char *buf, UInt16 data)
static char * encode32 (char *buf, UInt32 data)
static char * encode (char *buf, const char *data, unsigned int length)
static char * encodeAtrAddress4 (char *ptr, UInt16 type, const StunAtrAddress4 &atr)
static char * encodeAtrChangeRequest (char *ptr, const StunAtrChangeRequest &atr)
static char * encodeAtrError (char *ptr, const StunAtrError &atr)
static char * encodeAtrUnknown (char *ptr, const StunAtrUnknown &atr)
static char * encodeXorOnly (char *ptr)
static char * encodeAtrString (char *ptr, UInt16 type, const StunAtrString &atr)
static char * encodeAtrIntegrity (char *ptr, const StunAtrIntegrity &atr)
unsigned int stunEncodeMessage (const StunMessage &msg, char *buf, unsigned int bufLen, const StunAtrString &password, bool verbose)
int stunRand ()
int stunRandomPort ()
 return a random number to use as a port
static void toHex (const char *buffer, int bufferSize, char *output)
void stunCreateUserName (const StunAddress4 &source, StunAtrString *username)
void stunCreatePassword (const StunAtrString &username, StunAtrString *password)
UInt64 stunGetSystemTimeSecs ()
ostream & operator<< (ostream &strm, const UInt128 &r)
ostream & operator<< (ostream &strm, const StunAddress4 &addr)
bool stunParseHostName (char *peerName, UInt32 &ip, UInt16 &portVal, UInt16 defaultPort)
bool stunParseServerName (char *name, StunAddress4 &addr)
 find the IP address of a the specified stun server - return false is fails parse
static void stunCreateErrorResponse (StunMessage &response, int cl, int number, const char *msg)
static void stunCreateSharedSecretResponse (const StunMessage &request, const StunAddress4 &source, StunMessage &response)
bool stunServerProcessMsg (char *buf, unsigned int bufLen, StunAddress4 &from, StunAddress4 &secondary, StunAddress4 &myAddr, StunAddress4 &altAddr, StunMessage *resp, StunAddress4 *destination, StunAtrString *hmacPassword, bool *changePort, bool *changeIp, bool verbose)
bool stunInitServer (StunServerInfo &info, const StunAddress4 &myAddr, const StunAddress4 &altAddr, int startMediaPort, bool verbose)
 return true if all is OK Create a media relay and do the STERN thing if startMediaPort is non-zero
void stunStopServer (StunServerInfo &info)
bool stunServerProcess (StunServerInfo &info, bool verbose)
 return true if all is OK
int stunFindLocalInterfaces (UInt32 *addresses, int maxRet)
 returns number of address found - take array or addres
void stunBuildReqSimple (StunMessage *msg, const StunAtrString &username, bool changePort, bool changeIp, unsigned int id)
static void stunSendTest (Socket myFd, StunAddress4 &dest, const StunAtrString &username, const StunAtrString &password, int testNum, bool verbose)
void stunGetUserNameAndPassword (const StunAddress4 &dest, StunAtrString *username, StunAtrString *password)
void stunTest (StunAddress4 &dest, int testNum, bool verbose, StunAddress4 *sAddr)
NatType stunNatType (StunAddress4 &dest, bool verbose, bool *preservePort, bool *hairpin, int port, StunAddress4 *sAddr)
int stunOpenSocket (StunAddress4 &dest, StunAddress4 *mapAddr, int port, StunAddress4 *srcAddr, bool verbose)
bool stunOpenSocketPair (StunAddress4 &dest, StunAddress4 *mapAddr, int *fd1, int *fd2, int port, StunAddress4 *srcAddr, bool verbose)

Define Documentation

#define NOSSL

Definition at line 35 of file stun.cc.


Function Documentation

static void computeHmac ( char *  hmac,
const char *  input,
int  length,
const char *  key,
int  keySize 
) [static]

Definition at line 722 of file stun.cc.

Referenced by stunCreatePassword(), stunCreateUserName(), and stunEncodeMessage().

00723 {
00724    strncpy(hmac,"hmac-not-implemented",20);
00725 }

static char* encode ( char *  buf,
const char *  data,
unsigned int  length 
) [static]

Definition at line 457 of file stun.cc.

Referenced by encodeAtrError(), encodeAtrIntegrity(), encodeAtrString(), and stunEncodeMessage().

00458 {
00459    memcpy(buf, data, length);
00460    return buf + length;
00461 }

static char* encode16 ( char *  buf,
UInt16  data 
) [static]

Definition at line 440 of file stun.cc.

Referenced by encodeAtrAddress4(), encodeAtrChangeRequest(), encodeAtrError(), encodeAtrIntegrity(), encodeAtrString(), encodeAtrUnknown(), encodeXorOnly(), and stunEncodeMessage().

00441 {
00442    UInt16 ndata = htons(data);
00443    memcpy(buf, reinterpret_cast<void*>(&ndata), sizeof(UInt16));
00444    return buf + sizeof(UInt16);
00445 }

static char* encode32 ( char *  buf,
UInt32  data 
) [static]

Definition at line 448 of file stun.cc.

Referenced by encodeAtrAddress4(), and encodeAtrChangeRequest().

00449 {
00450    UInt32 ndata = htonl(data);
00451    memcpy(buf, reinterpret_cast<void*>(&ndata), sizeof(UInt32));
00452    return buf + sizeof(UInt32);
00453 }

static char* encodeAtrAddress4 ( char *  ptr,
UInt16  type,
const StunAtrAddress4 atr 
) [static]

Definition at line 465 of file stun.cc.

Referenced by stunEncodeMessage().

00466 {
00467    ptr = encode16(ptr, type);
00468    ptr = encode16(ptr, 8);
00469    *ptr++ = atr.pad;
00470    *ptr++ = IPv4Family;
00471    ptr = encode16(ptr, atr.ipv4.port);
00472    ptr = encode32(ptr, atr.ipv4.addr);
00473 
00474    return ptr;
00475 }

static char* encodeAtrChangeRequest ( char *  ptr,
const StunAtrChangeRequest atr 
) [static]

Definition at line 478 of file stun.cc.

Referenced by stunEncodeMessage().

00479 {
00480    ptr = encode16(ptr, ChangeRequest);
00481    ptr = encode16(ptr, 4);
00482    ptr = encode32(ptr, atr.value);
00483    return ptr;
00484 }

static char* encodeAtrError ( char *  ptr,
const StunAtrError atr 
) [static]

Definition at line 487 of file stun.cc.

Referenced by stunEncodeMessage().

00488 {
00489    ptr = encode16(ptr, ErrorCode);
00490    ptr = encode16(ptr, 6 + atr.sizeReason);
00491    ptr = encode16(ptr, atr.pad);
00492    *ptr++ = atr.errorClass;
00493    *ptr++ = atr.number;
00494    ptr = encode(ptr, atr.reason, atr.sizeReason);
00495    return ptr;
00496 }

static char* encodeAtrIntegrity ( char *  ptr,
const StunAtrIntegrity atr 
) [static]

Definition at line 533 of file stun.cc.

Referenced by stunEncodeMessage().

00534 {
00535    ptr = encode16(ptr, MessageIntegrity);
00536    ptr = encode16(ptr, 20);
00537    ptr = encode(ptr, atr.hash, sizeof(atr.hash));
00538    return ptr;
00539 }

static char* encodeAtrString ( char *  ptr,
UInt16  type,
const StunAtrString atr 
) [static]

Definition at line 521 of file stun.cc.

Referenced by stunEncodeMessage().

00522 {
00523    assert(atr.sizeValue % 4 == 0);
00524 
00525    ptr = encode16(ptr, type);
00526    ptr = encode16(ptr, atr.sizeValue);
00527    ptr = encode(ptr, atr.value, atr.sizeValue);
00528    return ptr;
00529 }

static char* encodeAtrUnknown ( char *  ptr,
const StunAtrUnknown atr 
) [static]

Definition at line 500 of file stun.cc.

Referenced by stunEncodeMessage().

00501 {
00502    ptr = encode16(ptr, UnknownAttribute);
00503    ptr = encode16(ptr, 2+2*atr.numAttributes);
00504    for (int i=0; i<atr.numAttributes; i++)
00505    {
00506       ptr = encode16(ptr, atr.attrType[i]);
00507    }
00508    return ptr;
00509 }

static char* encodeXorOnly ( char *  ptr  )  [static]

Definition at line 513 of file stun.cc.

Referenced by stunEncodeMessage().

00514 {
00515    ptr = encode16(ptr, XorOnly );
00516    return ptr;
00517 }

ostream& operator<< ( ostream &  strm,
const StunAddress4 addr 
)

Definition at line 846 of file stun.cc.

00847 {
00848    UInt32 ip = addr.addr;
00849    strm << ((int)(ip>>24)&0xFF) << ".";
00850    strm << ((int)(ip>>16)&0xFF) << ".";
00851    strm << ((int)(ip>> 8)&0xFF) << ".";
00852    strm << ((int)(ip>> 0)&0xFF) ;
00853 
00854    strm << ":" << addr.port;
00855 
00856    return strm;
00857 }

ostream& operator<< ( ostream &  strm,
const UInt128 r 
)

Definition at line 834 of file stun.cc.

00835 {
00836    strm << int(r.octet[0]);
00837    for ( int i=1; i<16; i++ )
00838    {
00839       strm << ':' << int(r.octet[i]);
00840    }
00841 
00842    return strm;
00843 }

void stunBuildReqSimple ( StunMessage msg,
const StunAtrString username,
bool  changePort,
bool  changeIp,
unsigned int  id 
)

Definition at line 1696 of file stun.cc.

Referenced by stunSendTest().

01699 {
01700    assert( msg );
01701    memset( msg , 0 , sizeof(*msg) );
01702 
01703    msg->msgHdr.msgType = BindRequestMsg;
01704 
01705    for ( int i=0; i<16; i=i+4 )
01706    {
01707       assert(i+3<16);
01708       int r = stunRand();
01709       msg->msgHdr.id.octet[i+0]= r>>0;
01710       msg->msgHdr.id.octet[i+1]= r>>8;
01711       msg->msgHdr.id.octet[i+2]= r>>16;
01712       msg->msgHdr.id.octet[i+3]= r>>24;
01713    }
01714 
01715    if ( id != 0 )
01716    {
01717       msg->msgHdr.id.octet[0] = id;
01718    }
01719 
01720    msg->hasChangeRequest = true;
01721    msg->changeRequest.value =(changeIp?ChangeIpFlag:0) |
01722       (changePort?ChangePortFlag:0);
01723 
01724    if ( username.sizeValue > 0 )
01725    {
01726       msg->hasUsername = true;
01727       msg->username = username;
01728    }
01729 }

static void stunCreateErrorResponse ( StunMessage response,
int  cl,
int  number,
const char *  msg 
) [static]

Definition at line 979 of file stun.cc.

Referenced by stunServerProcessMsg().

00980 {
00981    response.msgHdr.msgType = BindErrorResponseMsg;
00982    response.hasErrorCode = true;
00983    response.errorCode.errorClass = cl;
00984    response.errorCode.number = number;
00985    strcpy(response.errorCode.reason, msg);
00986 }

void stunCreatePassword ( const StunAtrString username,
StunAtrString password 
)

Definition at line 801 of file stun.cc.

Referenced by stunCreateSharedSecretResponse(), stunGetUserNameAndPassword(), and stunServerProcessMsg().

00802 {
00803    char hmac[20];
00804    char key[] = "Fluffy";
00805    //char buffer[STUN_MAX_STRING];
00806    computeHmac(hmac, username.value, strlen(username.value), key, strlen(key));
00807    toHex(hmac, 20, password->value);
00808    password->sizeValue = 40;
00809    password->value[40]=0;
00810 
00811    //clog << "password=" << password->value << endl;
00812 }

static void stunCreateSharedSecretResponse ( const StunMessage request,
const StunAddress4 source,
StunMessage response 
) [static]

Definition at line 1001 of file stun.cc.

Referenced by stunServerProcessMsg().

01002 {
01003    response.msgHdr.msgType = SharedSecretResponseMsg;
01004    response.msgHdr.id = request.msgHdr.id;
01005 
01006    response.hasUsername = true;
01007    stunCreateUserName( source, &response.username);
01008 
01009    response.hasPassword = true;
01010    stunCreatePassword( response.username, &response.password);
01011 }

void stunCreateUserName ( const StunAddress4 source,
StunAtrString username 
)

Definition at line 763 of file stun.cc.

Referenced by stunCreateSharedSecretResponse(), and stunGetUserNameAndPassword().

00764 {
00765    UInt64 time = stunGetSystemTimeSecs();
00766    time -= (time % 20*60);
00767    //UInt64 hitime = time >> 32;
00768    UInt64 lotime = time & 0xFFFFFFFF;
00769 
00770    char buffer[1024];
00771    sprintf(buffer,
00772            "%08x:%08x:%08x:",
00773            UInt32(source.addr),
00774            UInt32(stunRand()),
00775            UInt32(lotime));
00776    assert( strlen(buffer) < 1024 );
00777 
00778    assert(strlen(buffer) + 41 < STUN_MAX_STRING);
00779 
00780    char hmac[20];
00781    char key[] = "Jason";
00782    computeHmac(hmac, buffer, strlen(buffer), key, strlen(key) );
00783    char hmacHex[41];
00784    toHex(hmac, 20, hmacHex );
00785    hmacHex[40] =0;
00786 
00787    strcat(buffer,hmacHex);
00788 
00789    int l = strlen(buffer);
00790    assert( l+1 < STUN_MAX_STRING );
00791    assert( l%4 == 0 );
00792 
00793    username->sizeValue = l;
00794    memcpy(username->value,buffer,l);
00795    username->value[l]=0;
00796 
00797    //if (verbose) clog << "computed username=" << username.value << endl;
00798 }

unsigned int stunEncodeMessage ( const StunMessage msg,
char *  buf,
unsigned int  bufLen,
const StunAtrString password,
bool  verbose 
)

Definition at line 543 of file stun.cc.

Referenced by stunSendTest(), and stunServerProcess().

00548 {
00549    assert(bufLen >= sizeof(StunMsgHdr));
00550    char* ptr = buf;
00551 
00552    ptr = encode16(ptr, msg.msgHdr.msgType);
00553    char* lengthp = ptr;
00554    ptr = encode16(ptr, 0);
00555    ptr = encode(ptr, reinterpret_cast<const char*>(msg.msgHdr.id.octet), sizeof(msg.msgHdr.id));
00556 
00557    if (verbose) clog << "Encoding stun message: " << endl;
00558    if (msg.hasMappedAddress)
00559    {
00560       if (verbose) clog << "Encoding MappedAddress: " << msg.mappedAddress.ipv4 << endl;
00561       ptr = encodeAtrAddress4 (ptr, MappedAddress, msg.mappedAddress);
00562    }
00563    if (msg.hasResponseAddress)
00564    {
00565       if (verbose) clog << "Encoding ResponseAddress: " << msg.responseAddress.ipv4 << endl;
00566       ptr = encodeAtrAddress4(ptr, ResponseAddress, msg.responseAddress);
00567    }
00568    if (msg.hasChangeRequest)
00569    {
00570       if (verbose) clog << "Encoding ChangeRequest: " << msg.changeRequest.value << endl;
00571       ptr = encodeAtrChangeRequest(ptr, msg.changeRequest);
00572    }
00573    if (msg.hasSourceAddress)
00574    {
00575       if (verbose) clog << "Encoding SourceAddress: " << msg.sourceAddress.ipv4 << endl;
00576       ptr = encodeAtrAddress4(ptr, SourceAddress, msg.sourceAddress);
00577    }
00578    if (msg.hasChangedAddress)
00579    {
00580       if (verbose) clog << "Encoding ChangedAddress: " << msg.changedAddress.ipv4 << endl;
00581       ptr = encodeAtrAddress4(ptr, ChangedAddress, msg.changedAddress);
00582    }
00583    if (msg.hasUsername)
00584    {
00585       if (verbose) clog << "Encoding Username: " << msg.username.value << endl;
00586       ptr = encodeAtrString(ptr, Username, msg.username);
00587    }
00588    if (msg.hasPassword)
00589    {
00590       if (verbose) clog << "Encoding Password: " << msg.password.value << endl;
00591       ptr = encodeAtrString(ptr, Password, msg.password);
00592    }
00593    if (msg.hasErrorCode)
00594    {
00595       if (verbose) clog << "Encoding ErrorCode: class="
00596                         << int(msg.errorCode.errorClass)
00597                         << " number=" << int(msg.errorCode.number)
00598                         << " reason="
00599                         << msg.errorCode.reason
00600                         << endl;
00601 
00602       ptr = encodeAtrError(ptr, msg.errorCode);
00603    }
00604    if (msg.hasUnknownAttributes)
00605    {
00606       if (verbose) clog << "Encoding UnknownAttribute: ???" << endl;
00607       ptr = encodeAtrUnknown(ptr, msg.unknownAttributes);
00608    }
00609    if (msg.hasReflectedFrom)
00610    {
00611       if (verbose) clog << "Encoding ReflectedFrom: " << msg.reflectedFrom.ipv4 << endl;
00612       ptr = encodeAtrAddress4(ptr, ReflectedFrom, msg.reflectedFrom);
00613    }
00614    if (msg.hasXorMappedAddress)
00615    {
00616       if (verbose) clog << "Encoding XorMappedAddress: " << msg.xorMappedAddress.ipv4 << endl;
00617       ptr = encodeAtrAddress4 (ptr, XorMappedAddress, msg.xorMappedAddress);
00618    }
00619    if (msg.xorOnly)
00620    {
00621       if (verbose) clog << "Encoding xorOnly: " << endl;
00622       ptr = encodeXorOnly( ptr );
00623    }
00624    if (msg.hasServerName)
00625    {
00626       if (verbose) clog << "Encoding ServerName: " << msg.serverName.value << endl;
00627       ptr = encodeAtrString(ptr, ServerName, msg.serverName);
00628    }
00629    if (msg.hasSecondaryAddress)
00630    {
00631       if (verbose) clog << "Encoding SecondaryAddress: " << msg.secondaryAddress.ipv4 << endl;
00632       ptr = encodeAtrAddress4 (ptr, SecondaryAddress, msg.secondaryAddress);
00633    }
00634 
00635    if (password.sizeValue > 0)
00636    {
00637       if (verbose) clog << "HMAC with password: " << password.value << endl;
00638 
00639       StunAtrIntegrity integrity;
00640       computeHmac(integrity.hash, buf, int(ptr-buf) , password.value, password.sizeValue);
00641       ptr = encodeAtrIntegrity(ptr, integrity);
00642    }
00643    if (verbose) clog << endl;
00644 
00645    encode16(lengthp, UInt16(ptr - buf - sizeof(StunMsgHdr)));
00646    return int(ptr - buf);
00647 }

int stunFindLocalInterfaces ( UInt32 addresses,
int  maxRet 
)

returns number of address found - take array or addres

Definition at line 1629 of file stun.cc.

01630 {
01631 #if defined(WIN32) || defined(__sparc__)
01632    return 0;
01633 #else
01634    struct ifconf ifc;
01635 
01636    int s = socket( AF_INET, SOCK_DGRAM, 0 );
01637    int len = 100 * sizeof(struct ifreq);
01638 
01639    char buf[ len ];
01640 
01641    ifc.ifc_len = len;
01642    ifc.ifc_buf = buf;
01643 
01644    int e = ioctl(s,SIOCGIFCONF,&ifc);
01645    char *ptr = buf;
01646    int tl = ifc.ifc_len;
01647    int count=0;
01648 
01649    while ( (tl > 0) && ( count < maxRet) )
01650    {
01651       struct ifreq* ifr = (struct ifreq *)ptr;
01652 
01653       int si = sizeof(ifr->ifr_name) + sizeof(struct sockaddr);
01654       tl -= si;
01655       ptr += si;
01656       //char* name = ifr->ifr_ifrn.ifrn_name;
01657       //cerr << "name = " << name << endl;
01658 
01659       struct ifreq ifr2;
01660       ifr2 = *ifr;
01661 
01662       e = ioctl(s,SIOCGIFADDR,&ifr2);
01663       if ( e == -1 )
01664       {
01665          break;
01666       }
01667 
01668       //cerr << "ioctl addr e = " << e << endl;
01669 
01670       struct sockaddr a = ifr2.ifr_addr;
01671       struct sockaddr_in* addr = (struct sockaddr_in*) &a;
01672 
01673       UInt32 ai = ntohl( addr->sin_addr.s_addr );
01674       if (int((ai>>24)&0xFF) != 127)
01675       {
01676          addresses[count++] = ai;
01677       }
01678 
01679 #if 0
01680       cerr << "Detected interface "
01681            << int((ai>>24)&0xFF) << "."
01682            << int((ai>>16)&0xFF) << "."
01683            << int((ai>> 8)&0xFF) << "."
01684            << int((ai    )&0xFF) << endl;
01685 #endif
01686    }
01687 
01688    stunclosesocket(s);
01689 
01690    return count;
01691 #endif
01692 }

UInt64 stunGetSystemTimeSecs (  ) 

Definition at line 816 of file stun.cc.

Referenced by stunCreateUserName().

00817 {
00818    UInt64 time=0;
00819 #if defined(WIN32)
00820    SYSTEMTIME t;
00821    // CJ TODO - this probably has bug on wrap around every 24 hours
00822    GetSystemTime( &t );
00823    time = (t.wHour*60+t.wMinute)*60+t.wSecond;
00824 #else
00825    struct timeval now;
00826    gettimeofday( &now , NULL );
00827    //assert( now );
00828    time = now.tv_sec;
00829 #endif
00830    return time;
00831 }

void stunGetUserNameAndPassword ( const StunAddress4 dest,
StunAtrString username,
StunAtrString password 
)

Definition at line 1800 of file stun.cc.

Referenced by stunNatType(), stunOpenSocket(), stunOpenSocketPair(), and stunTest().

01803 {
01804    // !cj! This is totally bogus - need to make TLS connection to dest and get a
01805    // username and password to use
01806    stunCreateUserName(dest, username);
01807    stunCreatePassword(*username, password);
01808 }

bool stunInitServer ( StunServerInfo info,
const StunAddress4 myAddr,
const StunAddress4 altAddr,
int  startMediaPort,
bool  verbose 
)

return true if all is OK Create a media relay and do the STERN thing if startMediaPort is non-zero

Definition at line 1248 of file stun.cc.

01250 {
01251    assert( myAddr.port != 0 );
01252    assert( altAddr.port!= 0 );
01253    assert( myAddr.addr  != 0 );
01254    //assert( altAddr.addr != 0 );
01255 
01256    info.myAddr = myAddr;
01257    info.altAddr = altAddr;
01258 
01259    info.myFd = STUN_INVALID_SOCKET;
01260    info.altPortFd = STUN_INVALID_SOCKET;
01261    info.altIpFd = STUN_INVALID_SOCKET;
01262    info.altIpPortFd = STUN_INVALID_SOCKET;
01263 
01264    memset(info.relays, 0, sizeof(info.relays));
01265    if (startMediaPort > 0)
01266    {
01267       info.relay = true;
01268 
01269       for (int i=0; i<MAX_MEDIA_RELAYS; ++i)
01270       {
01271          StunMediaRelay* relay = &info.relays[i];
01272          relay->relayPort = startMediaPort+i;
01273          relay->fd = 0;
01274          relay->expireTime = 0;
01275       }
01276    }
01277    else
01278    {
01279       info.relay = false;
01280    }
01281 
01282    if ((info.myFd = openPort(myAddr.port, myAddr.addr,verbose)) == STUN_INVALID_SOCKET)
01283    {
01284       clog << "Can't open " << myAddr << endl;
01285       stunStopServer(info);
01286 
01287       return false;
01288    }
01289    //if (verbose) clog << "Opened " << myAddr.addr << ":" << myAddr.port << " --> " << info.myFd << endl;
01290 
01291    if ((info.altPortFd = openPort(altAddr.port,myAddr.addr,verbose)) == STUN_INVALID_SOCKET)
01292    {
01293       clog << "Can't open " << myAddr << endl;
01294       stunStopServer(info);
01295       return false;
01296    }
01297    //if (verbose) clog << "Opened " << myAddr.addr << ":" << altAddr.port << " --> " << info.altPortFd << endl;
01298 
01299 
01300    info.altIpFd = STUN_INVALID_SOCKET;
01301    if (  altAddr.addr != 0 )
01302    {
01303       if ((info.altIpFd = openPort( myAddr.port, altAddr.addr,verbose)) == STUN_INVALID_SOCKET)
01304       {
01305          clog << "Can't open " << altAddr << endl;
01306          stunStopServer(info);
01307          return false;
01308       }
01309       //if (verbose) clog << "Opened " << altAddr.addr << ":" << myAddr.port << " --> " << info.altIpFd << endl;;
01310    }
01311 
01312    info.altIpPortFd = STUN_INVALID_SOCKET;
01313    if (  altAddr.addr != 0 )
01314    {  if ((info.altIpPortFd = openPort(altAddr.port, altAddr.addr,verbose)) == STUN_INVALID_SOCKET)
01315       {
01316          clog << "Can't open " << altAddr << endl;
01317          stunStopServer(info);
01318          return false;
01319       }
01320       //if (verbose) clog << "Opened " << altAddr.addr << ":" << altAddr.port << " --> " << info.altIpPortFd << endl;;
01321    }
01322 
01323    return true;
01324 }

NatType stunNatType ( StunAddress4 dest,
bool  verbose,
bool *  preservePort,
bool *  hairpin,
int  port,
StunAddress4 sAddr 
)

Definition at line 1875 of file stun.cc.

Referenced by SingleHostUnderlayConfigurator::initializeUnderlay().

01882 {
01883    assert( dest.addr != 0 );
01884    assert( dest.port != 0 );
01885 
01886    if ( hairpin )
01887    {
01888       *hairpin = false;
01889    }
01890 
01891    if ( port == 0 )
01892    {
01893       port = stunRandomPort();
01894    }
01895    UInt32 interfaceIp=0;
01896    if (sAddr)
01897    {
01898       interfaceIp = sAddr->addr;
01899    }
01900    Socket myFd1 = openPort(port,interfaceIp,verbose);
01901    Socket myFd2 = openPort(port+1,interfaceIp,verbose);
01902 
01903    if ( ( myFd1 == STUN_INVALID_SOCKET) || ( myFd2 == STUN_INVALID_SOCKET) )
01904    {
01905         cerr << "Some problem opening port/interface to send on" << endl;
01906        return StunTypeFailure;
01907    }
01908 
01909    assert( myFd1 != STUN_INVALID_SOCKET );
01910    assert( myFd2 != STUN_INVALID_SOCKET );
01911 
01912    bool respTestI=false;
01913    bool isNat=true;
01914    StunAddress4 testIchangedAddr;
01915    StunAddress4 testImappedAddr;
01916    bool respTestI2=false;
01917    bool mappedIpSame = true;
01918    StunAddress4 testI2mappedAddr;
01919    StunAddress4 testI2dest=dest;
01920    bool respTestII=false;
01921    bool respTestIII=false;
01922 
01923    bool respTestHairpin=false;
01924    bool respTestPreservePort=false;
01925 
01926    memset(&testImappedAddr,0,sizeof(testImappedAddr));
01927 
01928    StunAtrString username;
01929    StunAtrString password;
01930 
01931    username.sizeValue = 0;
01932    password.sizeValue = 0;
01933 
01934 #ifdef USE_TLS
01935    stunGetUserNameAndPassword( dest, username, password );
01936 #endif
01937 
01938    int count=0;
01939    while ( count < 7 )
01940    {
01941       struct timeval tv;
01942       fd_set fdSet;
01943 #ifdef WIN32
01944       unsigned int fdSetSize;
01945 #else
01946       int fdSetSize;
01947 #endif
01948       FD_ZERO(&fdSet); fdSetSize=0;
01949       FD_SET(myFd1,&fdSet); fdSetSize = (myFd1+1>fdSetSize) ? myFd1+1 : fdSetSize;
01950       FD_SET(myFd2,&fdSet); fdSetSize = (myFd2+1>fdSetSize) ? myFd2+1 : fdSetSize;
01951       tv.tv_sec=0;
01952       tv.tv_usec=150*1000; // 150 ms
01953       if ( count == 0 ) tv.tv_usec=0;
01954 
01955       int  err = select(fdSetSize, &fdSet, NULL, NULL, &tv);
01956       int e = getErrno();
01957       if ( err == STUN_SOCKET_ERROR )
01958       {
01959          // error occured
01960          cerr << "Error " << e << " " << strerror(e) << " in select" << endl;
01961         return StunTypeFailure;
01962      }
01963       else if ( err == 0 )
01964       {
01965          // timeout occured
01966          count++;
01967 
01968          if ( !respTestI )
01969          {
01970             stunSendTest( myFd1, dest, username, password, 1 ,verbose );
01971          }
01972 
01973          if ( (!respTestI2) && respTestI )
01974          {
01975             // check the address to send to if valid
01976             if (  ( testI2dest.addr != 0 ) &&
01977                   ( testI2dest.port != 0 ) )
01978             {
01979                stunSendTest( myFd1, testI2dest, username, password, 10  ,verbose);
01980             }
01981          }
01982 
01983          if ( !respTestII )
01984          {
01985             stunSendTest( myFd2, dest, username, password, 2 ,verbose );
01986          }
01987 
01988          if ( !respTestIII )
01989          {
01990             stunSendTest( myFd2, dest, username, password, 3 ,verbose );
01991          }
01992 
01993          if ( respTestI && (!respTestHairpin) )
01994          {
01995             if (  ( testImappedAddr.addr != 0 ) &&
01996                   ( testImappedAddr.port != 0 ) )
01997             {
01998                stunSendTest( myFd1, testImappedAddr, username, password, 11 ,verbose );
01999             }
02000          }
02001       }
02002       else
02003       {
02004          //if (verbose) clog << "-----------------------------------------" << endl;
02005          assert( err>0 );
02006          // data is avialbe on some fd
02007 
02008          for ( int i=0; i<2; i++)
02009          {
02010             Socket myFd;
02011             if ( i==0 )
02012             {
02013                myFd=myFd1;
02014             }
02015             else
02016             {
02017                myFd=myFd2;
02018             }
02019 
02020             if ( myFd!=STUN_INVALID_SOCKET )
02021             {
02022                if ( FD_ISSET(myFd,&fdSet) )
02023                {
02024                   char msg[STUN_MAX_MESSAGE_SIZE];
02025                   int msgLen = sizeof(msg);
02026 
02027                   StunAddress4 from;
02028 
02029                   getMessage( myFd,
02030                               msg,
02031                               &msgLen,
02032                               &from.addr,
02033                               &from.port,verbose );
02034 
02035                   StunMessage resp;
02036                   memset(&resp, 0, sizeof(StunMessage));
02037 
02038                   stunParseMessage( msg,msgLen, resp,verbose );
02039 
02040                   if ( verbose )
02041                   {
02042                      clog << "Received message of type " << resp.msgHdr.msgType
02043                           << "  id=" << (int)(resp.msgHdr.id.octet[0]) << endl;
02044                   }
02045 
02046                   switch( resp.msgHdr.id.octet[0] )
02047                   {
02048                      case 1:
02049                      {
02050                         if ( !respTestI )
02051                         {
02052 
02053                            testIchangedAddr.addr = resp.changedAddress.ipv4.addr;
02054                            testIchangedAddr.port = resp.changedAddress.ipv4.port;
02055                            testImappedAddr.addr = resp.mappedAddress.ipv4.addr;
02056                            testImappedAddr.port = resp.mappedAddress.ipv4.port;
02057 
02058                            respTestPreservePort = ( testImappedAddr.port == port );
02059                            if ( preservePort )
02060                            {
02061                               *preservePort = respTestPreservePort;
02062                            }
02063 
02064                            testI2dest.addr = resp.changedAddress.ipv4.addr;
02065 
02066                            if (sAddr)
02067                            {
02068                               sAddr->port = testImappedAddr.port;
02069                               sAddr->addr = testImappedAddr.addr;
02070                            }
02071 
02072                            count = 0;
02073                         }
02074                         respTestI=true;
02075                      }
02076                      break;
02077                      case 2:
02078                      {
02079                         respTestII=true;
02080                      }
02081                      break;
02082                      case 3:
02083                      {
02084                         respTestIII=true;
02085                      }
02086                      break;
02087                      case 10:
02088                      {
02089                         if ( !respTestI2 )
02090                         {
02091                            testI2mappedAddr.addr = resp.mappedAddress.ipv4.addr;
02092                            testI2mappedAddr.port = resp.mappedAddress.ipv4.port;
02093 
02094                            mappedIpSame = false;
02095                            if ( (testI2mappedAddr.addr  == testImappedAddr.addr ) &&
02096                                 (testI2mappedAddr.port == testImappedAddr.port ))
02097                            {
02098                               mappedIpSame = true;
02099                            }
02100 
02101 
02102                         }
02103                         respTestI2=true;
02104                      }
02105                      break;
02106                      case 11:
02107                      {
02108 
02109                         if ( hairpin )
02110                         {
02111                            *hairpin = true;
02112                         }
02113                         respTestHairpin = true;
02114                      }
02115                      break;
02116                   }
02117                }
02118             }
02119          }
02120       }
02121    }
02122 
02123    // see if we can bind to this address
02124    //cerr << "try binding to " << testImappedAddr << endl;
02125    Socket s = openPort( 0/*use ephemeral*/, testImappedAddr.addr, false );
02126    if ( s != STUN_INVALID_SOCKET )
02127    {
02128       stunclosesocket(s);
02129       isNat = false;
02130       //cerr << "binding worked" << endl;
02131    }
02132    else
02133    {
02134       isNat = true;
02135       //cerr << "binding failed" << endl;
02136    }
02137 
02138    if (verbose)
02139    {
02140       clog << "test I = " << respTestI << endl;
02141       clog << "test II = " << respTestII << endl;
02142       clog << "test III = " << respTestIII << endl;
02143       clog << "test I(2) = " << respTestI2 << endl;
02144       clog << "is nat  = " << isNat <<endl;
02145       clog << "mapped IP same = " << mappedIpSame << endl;
02146       clog << "hairpin = " << respTestHairpin << endl;
02147       clog << "preserver port = " << respTestPreservePort << endl;
02148    }
02149 
02150 #if 0
02151    // implement logic flow chart from draft RFC
02152    if ( respTestI )
02153    {
02154       if ( isNat )
02155       {
02156          if (respTestII)
02157          {
02158             return StunTypeConeNat;
02159          }
02160          else
02161          {
02162             if ( mappedIpSame )
02163             {
02164                if ( respTestIII )
02165                {
02166                   return StunTypeRestrictedNat;
02167                }
02168                else
02169                {
02170                   return StunTypePortRestrictedNat;
02171                }
02172             }
02173             else
02174             {
02175                return StunTypeSymNat;
02176             }
02177          }
02178       }
02179       else
02180       {
02181          if (respTestII)
02182          {
02183             return StunTypeOpen;
02184          }
02185          else
02186          {
02187             return StunTypeSymFirewall;
02188          }
02189       }
02190    }
02191    else
02192    {
02193       return StunTypeBlocked;
02194    }
02195 #else
02196    if ( respTestI ) // not blocked
02197    {
02198       if ( isNat )
02199       {
02200          if ( mappedIpSame )
02201          {
02202             if (respTestII)
02203             {
02204                return StunTypeIndependentFilter;
02205             }
02206             else
02207             {
02208                if ( respTestIII )
02209                {
02210                   return StunTypeDependentFilter;
02211                }
02212                else
02213                {
02214                   return StunTypePortDependedFilter;
02215                }
02216             }
02217          }
02218          else // mappedIp is not same
02219          {
02220             return StunTypeDependentMapping;
02221          }
02222       }
02223       else  // isNat is false
02224       {
02225          if (respTestII)
02226          {
02227             return StunTypeOpen;
02228          }
02229          else
02230          {
02231             return StunTypeFirewall;
02232          }
02233       }
02234    }
02235    else
02236    {
02237       return StunTypeBlocked;
02238    }
02239 #endif
02240 
02241    return StunTypeUnknown;
02242 }

int stunOpenSocket ( StunAddress4 dest,
StunAddress4 mapAddr,
int  port,
StunAddress4 srcAddr,
bool  verbose 
)

Definition at line 2246 of file stun.cc.

02249 {
02250    assert( dest.addr != 0 );
02251    assert( dest.port != 0 );
02252    assert( mapAddr );
02253 
02254    if ( port == 0 )
02255    {
02256       port = stunRandomPort();
02257    }
02258    unsigned int interfaceIp = 0;
02259    if ( srcAddr )
02260    {
02261       interfaceIp = srcAddr->addr;
02262    }
02263 
02264    Socket myFd = openPort(port,interfaceIp,verbose);
02265    if (myFd == STUN_INVALID_SOCKET)
02266    {
02267       return myFd;
02268    }
02269 
02270    char msg[STUN_MAX_MESSAGE_SIZE];
02271    int msgLen = sizeof(msg);
02272 
02273    StunAtrString username;
02274    StunAtrString password;
02275 
02276    username.sizeValue = 0;
02277    password.sizeValue = 0;
02278 
02279 #ifdef USE_TLS
02280    stunGetUserNameAndPassword( dest, username, password );
02281 #endif
02282 
02283    stunSendTest(myFd, dest, username, password, 1, 0/*false*/ );
02284 
02285    StunAddress4 from;
02286 
02287    getMessage( myFd, msg, &msgLen, &from.addr, &from.port,verbose );
02288 
02289    StunMessage resp;
02290    memset(&resp, 0, sizeof(StunMessage));
02291 
02292    bool ok = stunParseMessage( msg, msgLen, resp,verbose );
02293    if (!ok)
02294    {
02295       return -1;
02296    }
02297 
02298    StunAddress4 mappedAddr = resp.mappedAddress.ipv4;
02299    StunAddress4 changedAddr = resp.changedAddress.ipv4;
02300 
02301    //clog << "--- stunOpenSocket --- " << endl;
02302    //clog << "\treq  id=" << req.id << endl;
02303    //clog << "\tresp id=" << id << endl;
02304    //clog << "\tmappedAddr=" << mappedAddr << endl;
02305 
02306    *mapAddr = mappedAddr;
02307 
02308    return myFd;
02309 }

bool stunOpenSocketPair ( StunAddress4 dest,
StunAddress4 mapAddr,
int *  fd1,
int *  fd2,
int  port,
StunAddress4 srcAddr,
bool  verbose 
)

Definition at line 2313 of file stun.cc.

02317 {
02318    assert( dest.addr!= 0 );
02319    assert( dest.port != 0 );
02320    assert( mapAddr );
02321 
02322    const int NUM=3;
02323 
02324    if ( port == 0 )
02325    {
02326       port = stunRandomPort();
02327    }
02328 
02329    *fd1=-1;
02330    *fd2=-1;
02331 
02332    char msg[STUN_MAX_MESSAGE_SIZE];
02333    int msgLen =sizeof(msg);
02334 
02335    StunAddress4 from;
02336    int fd[NUM];
02337    int i;
02338 
02339    unsigned int interfaceIp = 0;
02340    if ( srcAddr )
02341    {
02342       interfaceIp = srcAddr->addr;
02343    }
02344 
02345    for( i=0; i<NUM; i++)
02346    {
02347       fd[i] = openPort( (port == 0) ? 0 : (port + i),
02348                         interfaceIp, verbose);
02349       if (fd[i] < 0)
02350       {
02351          while (i > 0)
02352          {
02353             stunclosesocket(fd[--i]);
02354          }
02355          return false;
02356       }
02357    }
02358 
02359    StunAtrString username;
02360    StunAtrString password;
02361 
02362    username.sizeValue = 0;
02363    password.sizeValue = 0;
02364 
02365 #ifdef USE_TLS
02366    stunGetUserNameAndPassword( dest, username, password );
02367 #endif
02368 
02369    for( i=0; i<NUM; i++)
02370    {
02371       stunSendTest(fd[i], dest, username, password, 1/*testNum*/, verbose );
02372    }
02373 
02374    StunAddress4 mappedAddr[NUM];
02375    for( i=0; i<NUM; i++)
02376    {
02377       msgLen = sizeof(msg)/sizeof(*msg);
02378       getMessage( fd[i],
02379                   msg,
02380                   &msgLen,
02381                   &from.addr,
02382                   &from.port ,verbose);
02383 
02384       StunMessage resp;
02385       memset(&resp, 0, sizeof(StunMessage));
02386 
02387       bool ok = stunParseMessage( msg, msgLen, resp, verbose );
02388       if (!ok)
02389       {
02390          return false;
02391       }
02392 
02393       mappedAddr[i] = resp.mappedAddress.ipv4;
02394       StunAddress4 changedAddr = resp.changedAddress.ipv4;
02395    }
02396 
02397    if (verbose)
02398    {
02399       clog << "--- stunOpenSocketPair --- " << endl;
02400       for( i=0; i<NUM; i++)
02401       {
02402          clog << "\t mappedAddr=" << mappedAddr[i] << endl;
02403       }
02404    }
02405 
02406    if ( mappedAddr[0].port %2 == 0 )
02407    {
02408       if (  mappedAddr[0].port+1 ==  mappedAddr[1].port )
02409       {
02410          *mapAddr = mappedAddr[0];
02411          *fd1 = fd[0];
02412          *fd2 = fd[1];
02413          stunclosesocket( fd[2] );
02414          return true;
02415       }
02416    }
02417    else
02418    {
02419       if (( mappedAddr[1].port %2 == 0 )
02420           && (  mappedAddr[1].port+1 ==  mappedAddr[2].port ))
02421       {
02422          *mapAddr = mappedAddr[1];
02423          *fd1 = fd[1];
02424          *fd2 = fd[2];
02425          stunclosesocket( fd[0] );
02426          return true;
02427       }
02428    }
02429 
02430    // something failed, close all and return error
02431    for( i=0; i<NUM; i++)
02432    {
02433       stunclosesocket( fd[i] );
02434    }
02435 
02436    return false;
02437 }

static bool stunParseAtrAddress ( char *  body,
unsigned int  hdrLen,
StunAtrAddress4 result 
) [static]

Definition at line 48 of file stun.cc.

Referenced by stunParseMessage().

00049 {
00050    if ( hdrLen != 8 )
00051    {
00052       clog << "hdrLen wrong for Address" <<endl;
00053       return false;
00054    }
00055    result.pad = *body++;
00056    result.family = *body++;
00057    if (result.family == IPv4Family)
00058    {
00059       UInt16 nport;
00060       memcpy(&nport, body, 2); body+=2;
00061       result.ipv4.port = ntohs(nport);
00062 
00063       UInt32 naddr;
00064       memcpy(&naddr, body, 4); body+=4;
00065       result.ipv4.addr = ntohl(naddr);
00066       return true;
00067    }
00068    else if (result.family == IPv6Family)
00069    {
00070       clog << "ipv6 not supported" << endl;
00071    }
00072    else
00073    {
00074       clog << "bad address family: " << result.family << endl;
00075    }
00076 
00077    return false;
00078 }

static bool stunParseAtrChangeRequest ( char *  body,
unsigned int  hdrLen,
StunAtrChangeRequest result 
) [static]

Definition at line 81 of file stun.cc.

Referenced by stunParseMessage().

00082 {
00083    if ( hdrLen != 4 )
00084    {
00085       clog << "hdr length = " << hdrLen << " expecting " << sizeof(result) << endl;
00086 
00087       clog << "Incorrect size for ChangeRequest" << endl;
00088       return false;
00089    }
00090    else
00091    {
00092       memcpy(&result.value, body, 4);
00093       result.value = ntohl(result.value);
00094       return true;
00095    }
00096 }

static bool stunParseAtrError ( char *  body,
unsigned int  hdrLen,
StunAtrError result 
) [static]

Definition at line 99 of file stun.cc.

Referenced by stunParseMessage().

00100 {
00101    if ( hdrLen >= sizeof(result) )
00102    {
00103       clog << "head on Error too large" << endl;
00104       return false;
00105    }
00106    else
00107    {
00108       memcpy(&result.pad, body, 2); body+=2;
00109       result.pad = ntohs(result.pad);
00110       result.errorClass = *body++;
00111       result.number = *body++;
00112 
00113       result.sizeReason = hdrLen - 4;
00114       memcpy(&result.reason, body, result.sizeReason);
00115       result.reason[result.sizeReason] = 0;
00116       return true;
00117    }
00118 }

static bool stunParseAtrIntegrity ( char *  body,
unsigned int  hdrLen,
StunAtrIntegrity result 
) [static]

Definition at line 166 of file stun.cc.

Referenced by stunParseMessage().

00167 {
00168    if ( hdrLen != 20)
00169    {
00170       clog << "MessageIntegrity must be 20 bytes" << endl;
00171       return false;
00172    }
00173    else
00174    {
00175       memcpy(&result.hash, body, hdrLen);
00176       return true;
00177    }
00178 }

static bool stunParseAtrString ( char *  body,
unsigned int  hdrLen,
StunAtrString result 
) [static]

Definition at line 142 of file stun.cc.

Referenced by stunParseMessage().

00143 {
00144    if ( hdrLen >= STUN_MAX_STRING )
00145    {
00146       clog << "String is too large" << endl;
00147       return false;
00148    }
00149    else
00150    {
00151       if (hdrLen % 4 != 0)
00152       {
00153          clog << "Bad length string " << hdrLen << endl;
00154          return false;
00155       }
00156 
00157       result.sizeValue = hdrLen;
00158       memcpy(&result.value, body, hdrLen);
00159       result.value[hdrLen] = 0;
00160       return true;
00161    }
00162 }

static bool stunParseAtrUnknown ( char *  body,
unsigned int  hdrLen,
StunAtrUnknown result 
) [static]

Definition at line 121 of file stun.cc.

Referenced by stunParseMessage().

00122 {
00123    if ( hdrLen >= sizeof(result) )
00124    {
00125       return false;
00126    }
00127    else
00128    {
00129       if (hdrLen % 4 != 0) return false;
00130       result.numAttributes = hdrLen / 4;
00131       for (int i=0; i<result.numAttributes; i++)
00132       {
00133          memcpy(&result.attrType[i], body, 2); body+=2;
00134          result.attrType[i] = ntohs(result.attrType[i]);
00135       }
00136       return true;
00137    }
00138 }

bool stunParseHostName ( char *  peerName,
UInt32 ip,
UInt16 portVal,
UInt16  defaultPort 
)

Definition at line 862 of file stun.cc.

Referenced by stunParseServerName().

00866 {
00867    in_addr sin_addr;
00868 
00869    char host[512];
00870    strncpy(host,peerName,512);
00871    host[512-1]='\0';
00872    char* port = NULL;
00873 
00874    int portNum = defaultPort;
00875 
00876    // pull out the port part if present.
00877    char* sep = strchr(host,':');
00878 
00879    if ( sep == NULL )
00880    {
00881       portNum = defaultPort;
00882    }
00883    else
00884    {
00885       *sep = '\0';
00886       port = sep + 1;
00887       // set port part
00888 
00889       char* endPtr=NULL;
00890 
00891       portNum = strtol(port,&endPtr,10);
00892 
00893       if ( endPtr != NULL )
00894       {
00895          if ( *endPtr != '\0' )
00896          {
00897             portNum = defaultPort;
00898          }
00899       }
00900    }
00901 
00902    if ( portNum < 1024 ) return false;
00903    if ( portNum >= 0xFFFF ) return false;
00904 
00905    // figure out the host part
00906    struct hostent* h;
00907 
00908 #ifdef WIN32
00909    assert( strlen(host) >= 1 );
00910    if ( isdigit( host[0] ) )
00911    {
00912       // assume it is a ip address
00913       unsigned long a = inet_addr(host);
00914       //cerr << "a=0x" << hex << a << dec << endl;
00915 
00916       ip = ntohl( a );
00917    }
00918    else
00919    {
00920       // assume it is a host name
00921       h = gethostbyname( host );
00922 
00923       if ( h == NULL )
00924       {
00925          int err = getErrno();
00926          std::cerr << "error was " << err << std::endl;
00927          assert( err != WSANOTINITIALISED );
00928 
00929          ip = ntohl( 0x7F000001L );
00930 
00931          return false;
00932       }
00933       else
00934       {
00935          sin_addr = *(struct in_addr*)h->h_addr;
00936          ip = ntohl( sin_addr.s_addr );
00937       }
00938    }
00939 
00940 #else
00941    h = gethostbyname( host );
00942    if ( h == NULL )
00943    {
00944       int err = getErrno();
00945       std::cerr << "error was " << err << std::endl;
00946       ip = ntohl( 0x7F000001L );
00947       return false;
00948    }
00949    else
00950    {
00951       sin_addr = *(struct in_addr*)h->h_addr;
00952       ip = ntohl( sin_addr.s_addr );
00953    }
00954 #endif
00955 
00956    portVal = portNum;
00957 
00958    return true;
00959 }

bool stunParseMessage ( char *  buf,
unsigned int  bufLen,
StunMessage msg,
bool  verbose 
)

Definition at line 182 of file stun.cc.

Referenced by stunNatType(), stunOpenSocket(), stunOpenSocketPair(), stunServerProcessMsg(), and stunTest().

00183 {
00184    if (verbose) clog << "Received stun message: " << bufLen << " bytes" << endl;
00185    memset(&msg, 0, sizeof(msg));
00186 
00187    if (sizeof(StunMsgHdr) > bufLen)
00188    {
00189       clog << "Bad message" << endl;
00190       return false;
00191    }
00192 
00193    memcpy(&msg.msgHdr, buf, sizeof(StunMsgHdr));
00194    msg.msgHdr.msgType = ntohs(msg.msgHdr.msgType);
00195    msg.msgHdr.msgLength = ntohs(msg.msgHdr.msgLength);
00196 
00197    if (msg.msgHdr.msgLength + sizeof(StunMsgHdr) != bufLen)
00198    {
00199       clog << "Message header length doesn't match message size: "
00200            << msg.msgHdr.msgLength << " - " << bufLen << endl;
00201       return false;
00202    }
00203 
00204    char* body = buf + sizeof(StunMsgHdr);
00205    unsigned int size = msg.msgHdr.msgLength;
00206 
00207    //clog << "bytes after header = " << size << endl;
00208 
00209    while ( size > 0 )
00210    {
00211       // !jf! should check that there are enough bytes left in the buffer
00212 
00213       StunAtrHdr* attr = reinterpret_cast<StunAtrHdr*>(body);
00214 
00215       unsigned int attrLen = ntohs(attr->length);
00216       int atrType = ntohs(attr->type);
00217 
00218       //if (verbose) clog << "Found attribute type=" << AttrNames[atrType] << " length=" << attrLen << endl;
00219       if ( attrLen+4 > size )
00220       {
00221          clog << "claims attribute is larger than size of message "
00222               <<"(attribute type="<<atrType<<")"<< endl;
00223          return false;
00224       }
00225 
00226       body += 4; // skip the length and type in attribute header
00227       size -= 4;
00228 
00229       switch ( atrType )
00230       {
00231          case MappedAddress:
00232             msg.hasMappedAddress = true;
00233             if ( stunParseAtrAddress(  body,  attrLen,  msg.mappedAddress )== false )
00234             {
00235                clog << "problem parsing MappedAddress" << endl;
00236                return false;
00237             }
00238             else
00239             {
00240                if (verbose) clog << "MappedAddress = " << msg.mappedAddress.ipv4 << endl;
00241             }
00242 
00243             break;
00244 
00245          case ResponseAddress:
00246             msg.hasResponseAddress = true;
00247             if ( stunParseAtrAddress(  body,  attrLen,  msg.responseAddress )== false )
00248             {
00249                clog << "problem parsing ResponseAddress" << endl;
00250                return false;
00251             }
00252             else
00253             {
00254                if (verbose) clog << "ResponseAddress = " << msg.responseAddress.ipv4 << endl;
00255             }
00256             break;
00257 
00258          case ChangeRequest:
00259             msg.hasChangeRequest = true;
00260             if (stunParseAtrChangeRequest( body, attrLen, msg.changeRequest) == false)
00261             {
00262                clog << "problem parsing ChangeRequest" << endl;
00263                return false;
00264             }
00265             else
00266             {
00267                if (verbose) clog << "ChangeRequest = " << msg.changeRequest.value << endl;
00268             }
00269             break;
00270 
00271          case SourceAddress:
00272             msg.hasSourceAddress = true;
00273             if ( stunParseAtrAddress(  body,  attrLen,  msg.sourceAddress )== false )
00274             {
00275                clog << "problem parsing SourceAddress" << endl;
00276                return false;
00277             }
00278             else
00279             {
00280                if (verbose) clog << "SourceAddress = " << msg.sourceAddress.ipv4 << endl;
00281             }
00282             break;
00283 
00284          case ChangedAddress:
00285             msg.hasChangedAddress = true;
00286             if ( stunParseAtrAddress(  body,  attrLen,  msg.changedAddress )== false )
00287             {
00288                clog << "problem parsing ChangedAddress" << endl;
00289                return false;
00290             }
00291             else
00292             {
00293                if (verbose) clog << "ChangedAddress = " << msg.changedAddress.ipv4 << endl;
00294             }
00295             break;
00296 
00297          case Username:
00298             msg.hasUsername = true;
00299             if (stunParseAtrString( body, attrLen, msg.username) == false)
00300             {
00301                clog << "problem parsing Username" << endl;
00302                return false;
00303             }
00304             else
00305             {
00306                if (verbose) clog << "Username = " << msg.username.value << endl;
00307             }
00308 
00309             break;
00310 
00311          case Password:
00312             msg.hasPassword = true;
00313             if (stunParseAtrString( body, attrLen, msg.password) == false)
00314             {
00315                clog << "problem parsing Password" << endl;
00316                return false;
00317             }
00318             else
00319             {
00320                if (verbose) clog << "Password = " << msg.password.value << endl;
00321             }
00322             break;
00323 
00324          case MessageIntegrity:
00325             msg.hasMessageIntegrity = true;
00326             if (stunParseAtrIntegrity( body, attrLen, msg.messageIntegrity) == false)
00327             {
00328                clog << "problem parsing MessageIntegrity" << endl;
00329                return false;
00330             }
00331             else
00332             {
00333                //if (verbose) clog << "MessageIntegrity = " << msg.messageIntegrity.hash << endl;
00334             }
00335 
00336             // read the current HMAC
00337             // look up the password given the user of given the transaction id
00338             // compute the HMAC on the buffer
00339             // decide if they match or not
00340             break;
00341 
00342          case ErrorCode:
00343             msg.hasErrorCode = true;
00344             if (stunParseAtrError(body, attrLen, msg.errorCode) == false)
00345             {
00346                clog << "problem parsing ErrorCode" << endl;
00347                return false;
00348             }
00349             else
00350             {
00351                if (verbose) clog << "ErrorCode = " << int(msg.errorCode.errorClass)
00352                                  << " " << int(msg.errorCode.number)
00353                                  << " " << msg.errorCode.reason << endl;
00354             }
00355 
00356             break;
00357 
00358          case UnknownAttribute:
00359             msg.hasUnknownAttributes = true;
00360             if (stunParseAtrUnknown(body, attrLen, msg.unknownAttributes) == false)
00361             {
00362                clog << "problem parsing UnknownAttribute" << endl;
00363                return false;
00364             }
00365             break;
00366 
00367          case ReflectedFrom:
00368             msg.hasReflectedFrom = true;
00369             if ( stunParseAtrAddress(  body,  attrLen,  msg.reflectedFrom ) == false )
00370             {
00371                clog << "problem parsing ReflectedFrom" << endl;
00372                return false;
00373             }
00374             break;
00375 
00376          case XorMappedAddress:
00377             msg.hasXorMappedAddress = true;
00378             if ( stunParseAtrAddress(  body,  attrLen,  msg.xorMappedAddress ) == false )
00379             {
00380                clog << "problem parsing XorMappedAddress" << endl;
00381                return false;
00382             }
00383             else
00384             {
00385                if (verbose) clog << "XorMappedAddress = " << msg.mappedAddress.ipv4 << endl;
00386             }
00387             break;
00388 
00389          case XorOnly:
00390             msg.xorOnly = true;
00391             if (verbose)
00392             {
00393                clog << "xorOnly = true" << endl;
00394             }
00395             break;
00396 
00397          case ServerName:
00398             msg.hasServerName = true;
00399             if (stunParseAtrString( body, attrLen, msg.serverName) == false)
00400             {
00401                clog << "problem parsing ServerName" << endl;
00402                return false;
00403             }
00404             else
00405             {
00406                if (verbose) clog << "ServerName = " << msg.serverName.value << endl;
00407             }
00408             break;
00409 
00410          case SecondaryAddress:
00411             msg.hasSecondaryAddress = true;
00412             if ( stunParseAtrAddress(  body,  attrLen,  msg.secondaryAddress ) == false )
00413             {
00414                clog << "problem parsing secondaryAddress" << endl;
00415                return false;
00416             }
00417             else
00418             {
00419                if (verbose) clog << "SecondaryAddress = " << msg.secondaryAddress.ipv4 << endl;
00420             }
00421             break;
00422 
00423          default:
00424             if (verbose) clog << "Unknown attribute: " << atrType << endl;
00425             if ( atrType <= 0x7FFF )
00426             {
00427                return false;
00428             }
00429       }
00430 
00431       body += attrLen;
00432       size -= attrLen;
00433    }
00434 
00435    return true;
00436 }

bool stunParseServerName ( char *  name,
StunAddress4 addr 
)

find the IP address of a the specified stun server - return false is fails parse

Definition at line 963 of file stun.cc.

Referenced by SingleHostUnderlayConfigurator::initializeUnderlay().

00964 {
00965    assert(name);
00966 
00967    // TODO - put in DNS SRV stuff.
00968 
00969    bool ret = stunParseHostName( name, addr.addr, addr.port, 3478);
00970    if ( ret != true )
00971    {
00972        addr.port=0xFFFF;
00973    }
00974    return ret;
00975 }

int stunRand (  ) 

Definition at line 650 of file stun.cc.

Referenced by stunBuildReqSimple(), stunCreateUserName(), and stunRandomPort().

00651 {
00652    // return 32 bits of random stuff
00653    assert( sizeof(int) == 4 );
00654    static bool init=false;
00655    if ( !init )
00656    {
00657       init = true;
00658 
00659       UInt64 tick;
00660 
00661 #if defined(MSVC_WIN32)
00662       volatile unsigned int lowtick=0,hightick=0;
00663       __asm
00664          {
00665             rdtsc
00666                mov lowtick, eax
00667                mov hightick, edx
00668                }
00669       tick = hightick;
00670       tick <<= 32;
00671       tick |= lowtick;
00672 #elif (defined(WIN32) || defined(__GNUC__)) && ( defined(__i686__) || defined(__i386__) || defined(__x86_64__) )
00673       asm("rdtsc" : "=A" (tick));
00674 #elif defined (__SUNPRO_CC) || defined( __sparc__ )
00675       tick = gethrtime();
00676 #elif defined(__MACH__)
00677       int fd=open("/dev/random",O_RDONLY);
00678       read(fd,&tick,sizeof(tick));
00679       stunclosesocket(fd);
00680 #else
00681 #     error Need some way to seed the random number generator
00682 #endif
00683       int seed = int(tick);
00684 #ifdef WIN32
00685       srand(seed);
00686 #else
00687       srandom(seed);
00688 #endif
00689    }
00690 
00691 #ifdef WIN32
00692    assert( RAND_MAX == 0x7fff );
00693    int r1 = rand();
00694    int r2 = rand();
00695 
00696    int ret = (r1<<16) + r2;
00697 
00698    return ret;
00699 #else
00700    return random();
00701 #endif
00702 }

int stunRandomPort (  ) 

return a random number to use as a port

Definition at line 707 of file stun.cc.

Referenced by stunNatType(), stunOpenSocket(), stunOpenSocketPair(), and stunTest().

00708 {
00709    int min=0x4000;
00710    int max=0x7FFF;
00711 
00712    int ret = stunRand();
00713    ret = ret|min;
00714    ret = ret&max;
00715 
00716    return ret;
00717 }

static void stunSendTest ( Socket  myFd,
StunAddress4 dest,
const StunAtrString username,
const StunAtrString password,
int  testNum,
bool  verbose 
) [static]

Definition at line 1733 of file stun.cc.

Referenced by stunNatType(), stunOpenSocket(), stunOpenSocketPair(), and stunTest().

01736 {
01737    assert( dest.addr != 0 );
01738    assert( dest.port != 0 );
01739 
01740    bool changePort=false;
01741    bool changeIP=false;
01742    bool discard=false;
01743 
01744    switch (testNum)
01745    {
01746       case 1:
01747       case 10:
01748       case 11:
01749          break;
01750       case 2:
01751          //changePort=true;
01752          changeIP=true;
01753          break;
01754       case 3:
01755          changePort=true;
01756          break;
01757       case 4:
01758          changeIP=true;
01759          break;
01760       case 5:
01761          discard=true;
01762          break;
01763       default:
01764          cerr << "Test " << testNum <<" is unkown\n";
01765          assert(0);
01766    }
01767 
01768    StunMessage req;
01769    memset(&req, 0, sizeof(StunMessage));
01770 
01771    stunBuildReqSimple( &req, username,
01772                        changePort , changeIP ,
01773                        testNum );
01774 
01775    char buf[STUN_MAX_MESSAGE_SIZE];
01776    int len = STUN_MAX_MESSAGE_SIZE;
01777 
01778    len = stunEncodeMessage( req, buf, len, password,verbose );
01779 
01780    if ( verbose )
01781    {
01782       clog << "About to send msg of len " << len << " to " << dest << endl;
01783    }
01784 
01785    sendMessage( myFd, buf, len, dest.addr, dest.port, verbose );
01786 
01787    // add some delay so the packets don't get sent too quickly
01788 #ifdef WIN32 // !cj! TODO - should fix this up in windows
01789                  clock_t now = clock();
01790                  assert( CLOCKS_PER_SEC == 1000 );
01791                  while ( clock() <= now+10 ) { };
01792 #else
01793                  usleep(10*1000);
01794 #endif
01795 
01796 }

bool stunServerProcess ( StunServerInfo info,
bool  verbose 
)

return true if all is OK

Definition at line 1350 of file stun.cc.

01351 {
01352    char msg[STUN_MAX_MESSAGE_SIZE];
01353    int msgLen = sizeof(msg);
01354 
01355    bool ok = false;
01356    bool recvAltIp =false;
01357    bool recvAltPort = false;
01358 
01359    fd_set fdSet;
01360    Socket maxFd=0;
01361 
01362    FD_ZERO(&fdSet);
01363    FD_SET(info.myFd,&fdSet);
01364    if ( info.myFd >= maxFd ) maxFd=info.myFd+1;
01365    FD_SET(info.altPortFd,&fdSet);
01366    if ( info.altPortFd >= maxFd ) maxFd=info.altPortFd+1;
01367 
01368    if ( info.altIpFd != STUN_INVALID_SOCKET )
01369    {
01370       FD_SET(info.altIpFd,&fdSet);
01371       if (info.altIpFd>=maxFd) maxFd=info.altIpFd+1;
01372    }
01373    if ( info.altIpPortFd != STUN_INVALID_SOCKET )
01374    {
01375       FD_SET(info.altIpPortFd,&fdSet);
01376       if (info.altIpPortFd>=maxFd) maxFd=info.altIpPortFd+1;
01377    }
01378 
01379    if (info.relay)
01380    {
01381       for (int i=0; i<MAX_MEDIA_RELAYS; ++i)
01382       {
01383          StunMediaRelay* relay = &info.relays[i];
01384          if (relay->fd)
01385          {
01386             FD_SET(relay->fd, &fdSet);
01387             if (relay->fd >= maxFd)
01388                         {
01389                                 maxFd=relay->fd+1;
01390                         }
01391          }
01392       }
01393    }
01394 
01395    if ( info.altIpFd != STUN_INVALID_SOCKET )
01396    {
01397       FD_SET(info.altIpFd,&fdSet);
01398       if (info.altIpFd>=maxFd) maxFd=info.altIpFd+1;
01399    }
01400    if ( info.altIpPortFd != STUN_INVALID_SOCKET )
01401    {
01402       FD_SET(info.altIpPortFd,&fdSet);
01403       if (info.altIpPortFd>=maxFd) maxFd=info.altIpPortFd+1;
01404    }
01405 
01406    struct timeval tv;
01407    tv.tv_sec = 0;
01408    tv.tv_usec = 1000;
01409 
01410    int e = select( maxFd, &fdSet, NULL,NULL, &tv );
01411    if (e < 0)
01412    {
01413       int err = getErrno();
01414       clog << "Error on select: " << strerror(err) << endl;
01415    }
01416    else if (e >= 0)
01417    {
01418       StunAddress4 from;
01419 
01420       // do the media relaying
01421       if (info.relay)
01422       {
01423          time_t now = time(0);
01424          for (int i=0; i<MAX_MEDIA_RELAYS; ++i)
01425          {
01426             StunMediaRelay* relay = &info.relays[i];
01427             if (relay->fd)
01428             {
01429                if (FD_ISSET(relay->fd, &fdSet))
01430                {
01431                   char msg[MAX_RTP_MSG_SIZE];
01432                   int msgLen = sizeof(msg);
01433 
01434                   StunAddress4 rtpFrom;
01435                   ok = getMessage( relay->fd, msg, &msgLen, &rtpFrom.addr, &rtpFrom.port ,verbose);
01436                   if (ok)
01437                   {
01438                      sendMessage(info.myFd, msg, msgLen, relay->destination.addr, relay->destination.port, verbose);
01439                      relay->expireTime = now + MEDIA_RELAY_TIMEOUT;
01440                      if ( verbose ) clog << "Relay packet on "
01441                                          << relay->fd
01442                                          << " from " << rtpFrom
01443                                          << " -> " << relay->destination
01444                                          << endl;
01445                   }
01446                }
01447                else if (now > relay->expireTime)
01448                {
01449                   stunclosesocket(relay->fd);
01450                   relay->fd = 0;
01451                }
01452             }
01453          }
01454       }
01455 
01456 
01457       if (FD_ISSET(info.myFd,&fdSet))
01458       {
01459          if (verbose) clog << "received on A1:P1" << endl;
01460          recvAltIp = false;
01461          recvAltPort = false;
01462          ok = getMessage( info.myFd, msg, &msgLen, &from.addr, &from.port,verbose );
01463       }
01464       else if (FD_ISSET(info.altPortFd, &fdSet))
01465       {
01466          if (verbose) clog << "received on A1:P2" << endl;
01467          recvAltIp = false;
01468          recvAltPort = true;
01469          ok = getMessage( info.altPortFd, msg, &msgLen, &from.addr, &from.port,verbose );
01470       }
01471       else if ( (info.altIpFd!=STUN_INVALID_SOCKET) && FD_ISSET(info.altIpFd,&fdSet))
01472       {
01473          if (verbose) clog << "received on A2:P1" << endl;
01474          recvAltIp = true;
01475          recvAltPort = false;
01476          ok = getMessage( info.altIpFd, msg, &msgLen, &from.addr, &from.port ,verbose);
01477       }
01478       else if ( (info.altIpPortFd!=STUN_INVALID_SOCKET) && FD_ISSET(info.altIpPortFd, &fdSet))
01479       {
01480          if (verbose) clog << "received on A2:P2" << endl;
01481          recvAltIp = true;
01482          recvAltPort = true;
01483          ok = getMessage( info.altIpPortFd, msg, &msgLen, &from.addr, &from.port,verbose );
01484       }
01485       else
01486       {
01487          return true;
01488       }
01489 
01490       int relayPort = 0;
01491       if (info.relay)
01492       {
01493          for (int i=0; i<MAX_MEDIA_RELAYS; ++i)
01494          {
01495             StunMediaRelay* relay = &info.relays[i];
01496             if (relay->destination.addr == from.addr &&
01497                 relay->destination.port == from.port)
01498             {
01499                relayPort = relay->relayPort;
01500                relay->expireTime = time(0) + MEDIA_RELAY_TIMEOUT;
01501                break;
01502             }
01503          }
01504 
01505          if (relayPort == 0)
01506          {
01507             for (int i=0; i<MAX_MEDIA_RELAYS; ++i)
01508             {
01509                StunMediaRelay* relay = &info.relays[i];
01510                if (relay->fd == 0)
01511                {
01512                   if ( verbose ) clog << "Open relay port " << relay->relayPort << endl;
01513 
01514                   relay->fd = openPort(relay->relayPort, info.myAddr.addr, verbose);
01515                   relay->destination.addr = from.addr;
01516                   relay->destination.port = from.port;
01517                   relay->expireTime = time(0) + MEDIA_RELAY_TIMEOUT;
01518                   relayPort = relay->relayPort;
01519                   break;
01520                }
01521             }
01522          }
01523       }
01524 
01525       if ( !ok )
01526       {
01527          if ( verbose ) clog << "Get message did not return a valid message" <<endl;
01528          return true;
01529       }
01530 
01531       if ( verbose ) clog << "Got a request (len=" << msgLen << ") from " << from << endl;
01532 
01533       if ( msgLen <= 0 )
01534       {
01535          return true;
01536       }
01537 
01538       bool changePort = false;
01539       bool changeIp = false;
01540 
01541       StunMessage resp;
01542       StunAddress4 dest;
01543       StunAtrString hmacPassword;
01544       hmacPassword.sizeValue = 0;
01545 
01546       StunAddress4 secondary;
01547       secondary.port = 0;
01548       secondary.addr = 0;
01549 
01550       if (info.relay && relayPort)
01551       {
01552          secondary = from;
01553 
01554          from.addr = info.myAddr.addr;
01555          from.port = relayPort;
01556       }
01557 
01558       ok = stunServerProcessMsg( msg, msgLen, from, secondary,
01559                                  recvAltIp ? info.altAddr : info.myAddr,
01560                                  recvAltIp ? info.myAddr : info.altAddr,
01561                                  &resp,
01562                                  &dest,
01563                                  &hmacPassword,
01564                                  &changePort,
01565                                  &changeIp,
01566                                  verbose );
01567 
01568       if ( !ok )
01569       {
01570          if ( verbose ) clog << "Failed to parse message" << endl;
01571          return true;
01572       }
01573 
01574       char buf[STUN_MAX_MESSAGE_SIZE];
01575       int len = sizeof(buf);
01576 
01577       len = stunEncodeMessage( resp, buf, len, hmacPassword,verbose );
01578 
01579       if ( dest.addr == 0 )  ok=false;
01580       if ( dest.port == 0 ) ok=false;
01581 
01582       if ( ok )
01583       {
01584          assert( dest.addr != 0 );
01585          assert( dest.port != 0 );
01586 
01587          Socket sendFd;
01588 
01589          bool sendAltIp   = recvAltIp;   // send on the received IP address
01590          bool sendAltPort = recvAltPort; // send on the received port
01591 
01592          if ( changeIp )   sendAltIp   = !sendAltIp;   // if need to change IP, then flip logic
01593          if ( changePort ) sendAltPort = !sendAltPort; // if need to change port, then flip logic
01594 
01595          if ( !sendAltPort )
01596          {
01597             if ( !sendAltIp )
01598             {
01599                sendFd = info.myFd;
01600             }
01601             else
01602             {
01603                sendFd = info.altIpFd;
01604             }
01605          }
01606          else
01607          {
01608             if ( !sendAltIp )
01609             {
01610                sendFd = info.altPortFd;
01611             }
01612             else
01613             {
01614                sendFd = info.altIpPortFd;
01615             }
01616          }
01617 
01618          if ( sendFd != STUN_INVALID_SOCKET )
01619          {
01620             sendMessage( sendFd, buf, len, dest.addr, dest.port, verbose );
01621          }
01622       }
01623    }
01624 
01625    return true;
01626 }

bool stunServerProcessMsg ( char *  buf,
unsigned int  bufLen,
StunAddress4 from,
StunAddress4 secondary,
StunAddress4 myAddr,
StunAddress4 altAddr,
StunMessage resp,
StunAddress4 destination,
StunAtrString hmacPassword,
bool *  changePort,
bool *  changeIp,
bool  verbose 
)

Definition at line 1018 of file stun.cc.

Referenced by stunServerProcess().

01030 {
01031 
01032    // set up information for default response
01033 
01034    memset( resp, 0 , sizeof(*resp) );
01035 
01036    *changeIp = false;
01037    *changePort = false;
01038 
01039    StunMessage req;
01040    bool ok = stunParseMessage( buf,bufLen, req, verbose);
01041 
01042    if (!ok)      // Complete garbage, drop it on the floor
01043    {
01044       if (verbose) clog << "Request did not parse" << endl;
01045       return false;
01046    }
01047    if (verbose) clog << "Request parsed ok" << endl;
01048 
01049    StunAddress4 mapped = req.mappedAddress.ipv4;
01050    StunAddress4 respondTo = req.responseAddress.ipv4;
01051    UInt32 flags = req.changeRequest.value;
01052 
01053    switch (req.msgHdr.msgType)
01054    {
01055       case SharedSecretRequestMsg:
01056          if(verbose) clog << "Received SharedSecretRequestMsg on udp. send error 433." << endl;
01057          // !cj! - should fix so you know if this came over TLS or UDP
01058          stunCreateSharedSecretResponse(req, from, *resp);
01059          //stunCreateSharedSecretErrorResponse(*resp, 4, 33, "this request must be over TLS");
01060          return true;
01061 
01062       case BindRequestMsg:
01063          if (!req.hasMessageIntegrity)
01064          {
01065             if (verbose) clog << "BindRequest does not contain MessageIntegrity" << endl;
01066 
01067             if (0) // !jf! mustAuthenticate
01068             {
01069                if(verbose) clog << "Received BindRequest with no MessageIntegrity. Sending 401." << endl;
01070                stunCreateErrorResponse(*resp, 4, 1, "Missing MessageIntegrity");
01071                return true;
01072             }
01073          }
01074          else
01075          {
01076             if (!req.hasUsername)
01077             {
01078                if (verbose) clog << "No UserName. Send 432." << endl;
01079                stunCreateErrorResponse(*resp, 4, 32, "No UserName and contains MessageIntegrity");
01080                return true;
01081             }
01082             else
01083             {
01084                if (verbose) clog << "Validating username: " << req.username.value << endl;
01085                // !jf! could retrieve associated password from provisioning here
01086                if (strcmp(req.username.value, "test") == 0)
01087                {
01088                   if (0)
01089                   {
01090                      // !jf! if the credentials are stale
01091                      stunCreateErrorResponse(*resp, 4, 30, "Stale credentials on BindRequest");
01092                      return true;
01093                   }
01094                   else
01095                   {
01096                      if (verbose) clog << "Validating MessageIntegrity" << endl;
01097                      // need access to shared secret
01098 
01099                      unsigned char hmac[20];
01100 #ifndef NOSSL
01101                      unsigned int hmacSize=20;
01102 
01103                      HMAC(EVP_sha1(),
01104                           "1234", 4,
01105                           reinterpret_cast<const unsigned char*>(buf), bufLen-20-4,
01106                           hmac, &hmacSize);
01107                      assert(hmacSize == 20);
01108 #endif
01109 
01110                      if (memcmp(buf, hmac, 20) != 0)
01111                      {
01112                         if (verbose) clog << "MessageIntegrity is bad. Sending " << endl;
01113                         stunCreateErrorResponse(*resp, 4, 3, "Unknown username. Try test with password 1234");
01114                         return true;
01115                      }
01116 
01117                      // need to compute this later after message is filled in
01118                      resp->hasMessageIntegrity = true;
01119                      assert(req.hasUsername);
01120                      resp->hasUsername = true;
01121                      resp->username = req.username; // copy username in
01122                   }
01123                }
01124                else
01125                {
01126                   if (verbose) clog << "Invalid username: " << req.username.value << "Send 430." << endl;
01127                }
01128             }
01129          }
01130 
01131          // TODO !jf! should check for unknown attributes here and send 420 listing the
01132          // unknown attributes.
01133 
01134          if ( respondTo.port == 0 ) respondTo = from;
01135          if ( mapped.port == 0 ) mapped = from;
01136 
01137          *changeIp   = ( flags & ChangeIpFlag )?true:false;
01138          *changePort = ( flags & ChangePortFlag )?true:false;
01139 
01140          if (verbose)
01141          {
01142             clog << "Request is valid:" << endl;
01143             clog << "\t flags=" << flags << endl;
01144             clog << "\t changeIp=" << *changeIp << endl;
01145             clog << "\t changePort=" << *changePort << endl;
01146             clog << "\t from = " << from << endl;
01147             clog << "\t respond to = " << respondTo << endl;
01148             clog << "\t mapped = " << mapped << endl;
01149          }
01150 
01151          // form the outgoing message
01152          resp->msgHdr.msgType = BindResponseMsg;
01153          for ( int i=0; i<16; i++ )
01154          {
01155             resp->msgHdr.id.octet[i] = req.msgHdr.id.octet[i];
01156          }
01157 
01158          if ( req.xorOnly == false )
01159          {
01160             resp->hasMappedAddress = true;
01161             resp->mappedAddress.ipv4.port = mapped.port;
01162             resp->mappedAddress.ipv4.addr = mapped.addr;
01163          }
01164 
01165          if (1) // do xorMapped address or not
01166          {
01167             resp->hasXorMappedAddress = true;
01168             UInt16 id16 = req.msgHdr.id.octet[0]<<8
01169                | req.msgHdr.id.octet[1];
01170             UInt32 id32 = req.msgHdr.id.octet[0]<<24
01171                | req.msgHdr.id.octet[1]<<16
01172                | req.msgHdr.id.octet[2]<<8
01173                | req.msgHdr.id.octet[3];
01174             resp->xorMappedAddress.ipv4.port = mapped.port^id16;
01175             resp->xorMappedAddress.ipv4.addr = mapped.addr^id32;
01176          }
01177 
01178          resp->hasSourceAddress = true;
01179          resp->sourceAddress.ipv4.port = (*changePort) ? altAddr.port : myAddr.port;
01180          resp->sourceAddress.ipv4.addr = (*changeIp)   ? altAddr.addr : myAddr.addr;
01181 
01182          resp->hasChangedAddress = true;
01183          resp->changedAddress.ipv4.port = altAddr.port;
01184          resp->changedAddress.ipv4.addr = altAddr.addr;
01185 
01186          if ( secondary.port != 0 )
01187          {
01188             resp->hasSecondaryAddress = true;
01189             resp->secondaryAddress.ipv4.port = secondary.port;
01190             resp->secondaryAddress.ipv4.addr = secondary.addr;
01191          }
01192 
01193          if ( req.hasUsername && req.username.sizeValue > 0 )
01194          {
01195             // copy username in
01196             resp->hasUsername = true;
01197             assert( req.username.sizeValue % 4 == 0 );
01198             assert( req.username.sizeValue < STUN_MAX_STRING );
01199             memcpy( resp->username.value, req.username.value, req.username.sizeValue );
01200             resp->username.sizeValue = req.username.sizeValue;
01201          }
01202 
01203          if (1) // add ServerName
01204          {
01205             resp->hasServerName = true;
01206             const char serverName[] = "Vovida.org " STUN_VERSION; // must pad to mult of 4
01207 
01208             assert( sizeof(serverName) < STUN_MAX_STRING );
01209             //cerr << "sizeof serverName is "  << sizeof(serverName) << endl;
01210             assert( sizeof(serverName)%4 == 0 );
01211             memcpy( resp->serverName.value, serverName, sizeof(serverName));
01212             resp->serverName.sizeValue = sizeof(serverName);
01213          }
01214 
01215          if ( req.hasMessageIntegrity & req.hasUsername )
01216          {
01217             // this creates the password that will be used in the HMAC when then
01218             // messages is sent
01219             stunCreatePassword( req.username, hmacPassword );
01220          }
01221 
01222          if (req.hasUsername && (req.username.sizeValue > 64 ) )
01223          {
01224             UInt32 source;
01225             assert( sizeof(int) == sizeof(UInt32) );
01226 
01227             sscanf(req.username.value, "%x", &source);
01228             resp->hasReflectedFrom = true;
01229             resp->reflectedFrom.ipv4.port = 0;
01230             resp->reflectedFrom.ipv4.addr = source;
01231          }
01232 
01233          destination->port = respondTo.port;
01234          destination->addr = respondTo.addr;
01235 
01236          return true;
01237 
01238       default:
01239          if (verbose) clog << "Unknown or unsupported request " << endl;
01240          return false;
01241    }
01242 
01243    assert(0);
01244    return false;
01245 }

void stunStopServer ( StunServerInfo info  ) 

Definition at line 1327 of file stun.cc.

Referenced by stunInitServer().

01328 {
01329    if (info.myFd > 0) stunclosesocket(info.myFd);
01330    if (info.altPortFd > 0) stunclosesocket(info.altPortFd);
01331    if (info.altIpFd > 0) stunclosesocket(info.altIpFd);
01332    if (info.altIpPortFd > 0) stunclosesocket(info.altIpPortFd);
01333 
01334    if (info.relay)
01335    {
01336       for (int i=0; i<MAX_MEDIA_RELAYS; ++i)
01337       {
01338          StunMediaRelay* relay = &info.relays[i];
01339          if (relay->fd)
01340          {
01341             stunclosesocket(relay->fd);
01342             relay->fd = 0;
01343          }
01344       }
01345    }
01346 }

void stunTest ( StunAddress4 dest,
int  testNum,
bool  verbose,
StunAddress4 sAddr 
)

Definition at line 1812 of file stun.cc.

01813 {
01814    assert( dest.addr != 0 );
01815    assert( dest.port != 0 );
01816 
01817    int port = stunRandomPort();
01818    UInt32 interfaceIp=0;
01819    if (sAddr)
01820    {
01821       interfaceIp = sAddr->addr;
01822       if ( sAddr->port != 0 )
01823       {
01824         port = sAddr->port;
01825       }
01826    }
01827    Socket myFd = openPort(port,interfaceIp,verbose);
01828 
01829    StunAtrString username;
01830    StunAtrString password;
01831 
01832    username.sizeValue = 0;
01833    password.sizeValue = 0;
01834 
01835 #ifdef USE_TLS
01836    stunGetUserNameAndPassword( dest, username, password );
01837 #endif
01838 
01839    stunSendTest( myFd, dest, username, password, testNum, verbose );
01840 
01841    char msg[STUN_MAX_MESSAGE_SIZE];
01842    int msgLen = STUN_MAX_MESSAGE_SIZE;
01843 
01844    StunAddress4 from;
01845    getMessage( myFd,
01846                msg,
01847                &msgLen,
01848                &from.addr,
01849                &from.port,verbose );
01850 
01851    StunMessage resp;
01852    memset(&resp, 0, sizeof(StunMessage));
01853 
01854    if ( verbose ) clog << "Got a response" << endl;
01855    bool ok = stunParseMessage( msg,msgLen, resp,verbose );
01856 
01857    if ( verbose )
01858    {
01859       clog << "\t ok=" << ok << endl;
01860       clog << "\t id=" << resp.msgHdr.id << endl;
01861       clog << "\t mappedAddr=" << resp.mappedAddress.ipv4 << endl;
01862       clog << "\t changedAddr=" << resp.changedAddress.ipv4 << endl;
01863       clog << endl;
01864    }
01865 
01866    if (sAddr)
01867    {
01868       sAddr->port = resp.mappedAddress.ipv4.port;
01869       sAddr->addr = resp.mappedAddress.ipv4.addr;
01870    }
01871 }

static void toHex ( const char *  buffer,
int  bufferSize,
char *  output 
) [static]

Definition at line 743 of file stun.cc.

Referenced by stunCreatePassword(), and stunCreateUserName().

00744 {
00745    static char hexmap[] = "0123456789abcdef";
00746 
00747    const char* p = buffer;
00748    char* r = output;
00749    for (int i=0; i < bufferSize; i++)
00750    {
00751       unsigned char temp = *p++;
00752 
00753       int hi = (temp & 0xf0)>>4;
00754       int low = (temp & 0xf);
00755 
00756       *r++ = hexmap[hi];
00757       *r++ = hexmap[low];
00758    }
00759    *r = 0;
00760 }

Generated on Wed May 26 16:21:15 2010 for OverSim by  doxygen 1.6.3