stun.h File Reference

#include <iostream>
#include <time.h>

Go to the source code of this file.

Classes

struct  UInt128
struct  StunMsgHdr
struct  StunAtrHdr
struct  StunAddress4
struct  StunAtrAddress4
struct  StunAtrChangeRequest
struct  StunAtrError
struct  StunAtrUnknown
struct  StunAtrString
struct  StunAtrIntegrity
struct  StunMessage
struct  StunMediaRelay
struct  StunServerInfo

Defines

#define STUN_VERSION   "0.96"
#define STUN_MAX_STRING   256
#define STUN_MAX_UNKNOWN_ATTRIBUTES   8
#define STUN_MAX_MESSAGE_SIZE   2048
#define STUN_PORT   3478
#define MAX_MEDIA_RELAYS   500
#define MAX_RTP_MSG_SIZE   1500
#define MEDIA_RELAY_TIMEOUT   3*60

Typedefs

typedef unsigned char UInt8
typedef unsigned short UInt16
typedef unsigned int UInt32
typedef unsigned long long UInt64
typedef int Socket

Enumerations

enum  StunHmacStatus {
  HmacUnkown = 0, HmacOK, HmacBadUserName, HmacUnkownUserName,
  HmacFailed
}
enum  NatType {
  StunTypeUnknown = 0, StunTypeFailure, StunTypeOpen, StunTypeBlocked,
  StunTypeIndependentFilter, StunTypeDependentFilter, StunTypePortDependedFilter, StunTypeDependentMapping,
  StunTypeFirewall
}

Functions

bool stunParseMessage (char *buf, unsigned int bufLen, StunMessage &message, bool verbose)
void stunBuildReqSimple (StunMessage *msg, const StunAtrString &username, bool changePort, bool changeIp, unsigned int id=0)
unsigned int stunEncodeMessage (const StunMessage &message, char *buf, unsigned int bufLen, const StunAtrString &password, bool verbose)
void stunCreateUserName (const StunAddress4 &addr, StunAtrString *username)
void stunGetUserNameAndPassword (const StunAddress4 &dest, StunAtrString *username, StunAtrString *password)
void stunCreatePassword (const StunAtrString &username, StunAtrString *password)
int stunRand ()
UInt64 stunGetSystemTimeSecs ()
bool stunParseServerName (char *serverName, StunAddress4 &stunServerAddr)
 find the IP address of a the specified stun server - return false is fails parse
bool stunParseHostName (char *peerName, UInt32 &ip, UInt16 &portVal, UInt16 defaultPort)
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 maxSize)
 returns number of address found - take array or addres
void stunTest (StunAddress4 &dest, int testNum, bool verbose, StunAddress4 *srcAddr=0)
NatType stunNatType (StunAddress4 &dest, bool verbose, bool *preservePort=0, bool *hairpin=0, int port=0, StunAddress4 *sAddr=0)
std::ostream & operator<< (std::ostream &strm, const StunAddress4 &addr)
 prints a StunAddress
std::ostream & operator<< (std::ostream &strm, const UInt128 &)
bool stunServerProcessMsg (char *buf, unsigned int bufLen, StunAddress4 &from, StunAddress4 &myAddr, StunAddress4 &altAddr, StunMessage *resp, StunAddress4 *destination, StunAtrString *hmacPassword, bool *changePort, bool *changeIp, bool verbose)
int stunOpenSocket (StunAddress4 &dest, StunAddress4 *mappedAddr, int port=0, StunAddress4 *srcAddr=0, bool verbose=false)
bool stunOpenSocketPair (StunAddress4 &dest, StunAddress4 *mappedAddr, int *fd1, int *fd2, int srcPort=0, StunAddress4 *srcAddr=0, bool verbose=false)
int stunRandomPort ()
 return a random number to use as a port

Variables

const UInt8 IPv4Family = 0x01
 define a structure to hold a stun address
const UInt8 IPv6Family = 0x02
const UInt32 ChangeIpFlag = 0x04
const UInt32 ChangePortFlag = 0x02
const UInt16 MappedAddress = 0x0001
const UInt16 ResponseAddress = 0x0002
const UInt16 ChangeRequest = 0x0003
const UInt16 SourceAddress = 0x0004
const UInt16 ChangedAddress = 0x0005
const UInt16 Username = 0x0006
const UInt16 Password = 0x0007
const UInt16 MessageIntegrity = 0x0008
const UInt16 ErrorCode = 0x0009
const UInt16 UnknownAttribute = 0x000A
const UInt16 ReflectedFrom = 0x000B
const UInt16 XorMappedAddress = 0x8020
const UInt16 XorOnly = 0x0021
const UInt16 ServerName = 0x8022
const UInt16 SecondaryAddress = 0x8050
const UInt16 BindRequestMsg = 0x0001
const UInt16 BindResponseMsg = 0x0101
const UInt16 BindErrorResponseMsg = 0x0111
const UInt16 SharedSecretRequestMsg = 0x0002
const UInt16 SharedSecretResponseMsg = 0x0102
const UInt16 SharedSecretErrorResponseMsg = 0x0112

Define Documentation

#define MAX_MEDIA_RELAYS   500

Definition at line 204 of file stun.h.

Referenced by stunInitServer(), stunServerProcess(), and stunStopServer().

#define MAX_RTP_MSG_SIZE   1500

Definition at line 205 of file stun.h.

Referenced by stunServerProcess().

#define MEDIA_RELAY_TIMEOUT   3*60

Definition at line 206 of file stun.h.

Referenced by stunServerProcess().

#define STUN_MAX_MESSAGE_SIZE   2048
#define STUN_MAX_STRING   256

Definition at line 10 of file stun.h.

Referenced by stunCreateUserName(), stunParseAtrString(), and stunServerProcessMsg().

#define STUN_MAX_UNKNOWN_ATTRIBUTES   8

Definition at line 11 of file stun.h.

#define STUN_PORT   3478

Definition at line 14 of file stun.h.

#define STUN_VERSION   "0.96"

Definition at line 8 of file stun.h.

Referenced by stunServerProcessMsg().


Typedef Documentation

typedef int Socket

Definition at line 201 of file stun.h.

typedef unsigned short UInt16

Definition at line 18 of file stun.h.

typedef unsigned int UInt32

Definition at line 19 of file stun.h.

typedef unsigned long long UInt64

Definition at line 23 of file stun.h.

typedef unsigned char UInt8

Definition at line 17 of file stun.h.


Enumeration Type Documentation

enum NatType
Enumerator:
StunTypeUnknown 
StunTypeFailure 
StunTypeOpen 
StunTypeBlocked 
StunTypeIndependentFilter 
StunTypeDependentFilter 
StunTypePortDependedFilter 
StunTypeDependentMapping 
StunTypeFirewall 

Definition at line 178 of file stun.h.

00179 {
00180    StunTypeUnknown=0,
00181    StunTypeFailure,
00182    StunTypeOpen,
00183    StunTypeBlocked,
00184 
00185    StunTypeIndependentFilter,
00186    StunTypeDependentFilter,
00187    StunTypePortDependedFilter,
00188    StunTypeDependentMapping,
00189 
00190    //StunTypeConeNat,
00191    //StunTypeRestrictedNat,
00192    //StunTypePortRestrictedNat,
00193    //StunTypeSymNat,
00194    
00195    StunTypeFirewall,
00196 } NatType;

Enumerator:
HmacUnkown 
HmacOK 
HmacBadUserName 
HmacUnkownUserName 
HmacFailed 

Definition at line 118 of file stun.h.

00119 {
00120    HmacUnkown=0,
00121    HmacOK,
00122    HmacBadUserName,
00123    HmacUnkownUserName,
00124    HmacFailed,
00125 } StunHmacStatus;


Function Documentation

std::ostream& operator<< ( std::ostream &  strm,
const UInt128  
)
std::ostream& operator<< ( std::ostream &  strm,
const StunAddress4 addr 
)

prints a StunAddress

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

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 }

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 }

void stunCreateUserName ( const StunAddress4 addr,
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 message,
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  maxSize 
)

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 = 0,
bool *  hairpin = 0,
int  port = 0,
StunAddress4 sAddr = 0 
)

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 mappedAddr,
int  port = 0,
StunAddress4 srcAddr = 0,
bool  verbose = false 
)

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 mappedAddr,
int *  fd1,
int *  fd2,
int  srcPort = 0,
StunAddress4 srcAddr = 0,
bool  verbose = false 
)

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 }

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 message,
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 *  serverName,
StunAddress4 stunServerAddr 
)

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 }

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 myAddr,
StunAddress4 altAddr,
StunMessage resp,
StunAddress4 destination,
StunAtrString hmacPassword,
bool *  changePort,
bool *  changeIp,
bool  verbose 
)
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 srcAddr = 0 
)

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 }


Variable Documentation

const UInt16 BindErrorResponseMsg = 0x0111

Definition at line 55 of file stun.h.

Referenced by stunCreateErrorResponse().

const UInt16 BindRequestMsg = 0x0001

Definition at line 53 of file stun.h.

Referenced by stunBuildReqSimple(), and stunServerProcessMsg().

const UInt16 BindResponseMsg = 0x0101

Definition at line 54 of file stun.h.

Referenced by stunServerProcessMsg().

const UInt16 ChangedAddress = 0x0005

Definition at line 40 of file stun.h.

Referenced by stunEncodeMessage(), and stunParseMessage().

const UInt32 ChangeIpFlag = 0x04

Definition at line 32 of file stun.h.

Referenced by stunBuildReqSimple(), and stunServerProcessMsg().

const UInt32 ChangePortFlag = 0x02

Definition at line 33 of file stun.h.

Referenced by stunBuildReqSimple(), and stunServerProcessMsg().

const UInt16 ChangeRequest = 0x0003

Definition at line 38 of file stun.h.

Referenced by encodeAtrChangeRequest(), and stunParseMessage().

const UInt16 ErrorCode = 0x0009

Definition at line 44 of file stun.h.

Referenced by encodeAtrError(), and stunParseMessage().

const UInt8 IPv4Family = 0x01

define a structure to hold a stun address

Definition at line 28 of file stun.h.

Referenced by encodeAtrAddress4(), and stunParseAtrAddress().

const UInt8 IPv6Family = 0x02

Definition at line 29 of file stun.h.

Referenced by stunParseAtrAddress().

const UInt16 MappedAddress = 0x0001

Definition at line 36 of file stun.h.

Referenced by stunEncodeMessage(), and stunParseMessage().

const UInt16 MessageIntegrity = 0x0008

Definition at line 43 of file stun.h.

Referenced by encodeAtrIntegrity(), and stunParseMessage().

const UInt16 Password = 0x0007

Definition at line 42 of file stun.h.

Referenced by stunEncodeMessage(), and stunParseMessage().

const UInt16 ReflectedFrom = 0x000B

Definition at line 46 of file stun.h.

Referenced by stunEncodeMessage(), and stunParseMessage().

const UInt16 ResponseAddress = 0x0002

Definition at line 37 of file stun.h.

Referenced by stunEncodeMessage(), and stunParseMessage().

const UInt16 SecondaryAddress = 0x8050

Definition at line 50 of file stun.h.

Referenced by stunEncodeMessage(), and stunParseMessage().

const UInt16 ServerName = 0x8022

Definition at line 49 of file stun.h.

Referenced by stunEncodeMessage(), and stunParseMessage().

Definition at line 58 of file stun.h.

Definition at line 56 of file stun.h.

Referenced by stunServerProcessMsg().

Definition at line 57 of file stun.h.

Referenced by stunCreateSharedSecretResponse().

const UInt16 SourceAddress = 0x0004

Definition at line 39 of file stun.h.

Referenced by stunEncodeMessage(), and stunParseMessage().

const UInt16 UnknownAttribute = 0x000A

Definition at line 45 of file stun.h.

Referenced by encodeAtrUnknown(), and stunParseMessage().

const UInt16 Username = 0x0006

Definition at line 41 of file stun.h.

Referenced by stunEncodeMessage(), and stunParseMessage().

const UInt16 XorMappedAddress = 0x8020

Definition at line 47 of file stun.h.

Referenced by stunEncodeMessage(), and stunParseMessage().

const UInt16 XorOnly = 0x0021

Definition at line 48 of file stun.h.

Referenced by encodeXorOnly(), and stunParseMessage().

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