stund/0000755000175000017500000000000012445636075010023 5ustar kkkkstund/Stun.sln0000644000175000017500000000406011710231326011452 0ustar kkkkMicrosoft Visual Studio Solution File, Format Version 7.00 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WinStun", "WinStun\WinStun.vcproj", "{717021E7-DCC4-41E7-9CDA-FA7596F18C56}" EndProject Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "WinStunSetup", "WinStunSetup\WinStunSetup.vdproj", "{EB812030-9F2E-4FB7-813D-2E99AE2C5E4E}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "client", "client.vcproj", "{76E56991-C964-444B-82A6-AFDA5145E18A}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "server", "server.vcproj", "{2011B7B6-6932-431D-83A3-E825A271F8A8}" EndProject Global GlobalSection(SolutionConfiguration) = preSolution ConfigName.0 = Debug ConfigName.1 = Release EndGlobalSection GlobalSection(ProjectDependencies) = postSolution EndGlobalSection GlobalSection(ProjectConfiguration) = postSolution {717021E7-DCC4-41E7-9CDA-FA7596F18C56}.Debug.ActiveCfg = Debug|Win32 {717021E7-DCC4-41E7-9CDA-FA7596F18C56}.Debug.Build.0 = Debug|Win32 {717021E7-DCC4-41E7-9CDA-FA7596F18C56}.Release.ActiveCfg = Release|Win32 {717021E7-DCC4-41E7-9CDA-FA7596F18C56}.Release.Build.0 = Release|Win32 {EB812030-9F2E-4FB7-813D-2E99AE2C5E4E}.Debug.ActiveCfg = Debug {EB812030-9F2E-4FB7-813D-2E99AE2C5E4E}.Release.ActiveCfg = Release {EB812030-9F2E-4FB7-813D-2E99AE2C5E4E}.Release.Build.0 = Release {76E56991-C964-444B-82A6-AFDA5145E18A}.Debug.ActiveCfg = Debug|Win32 {76E56991-C964-444B-82A6-AFDA5145E18A}.Debug.Build.0 = Debug|Win32 {76E56991-C964-444B-82A6-AFDA5145E18A}.Release.ActiveCfg = Release|Win32 {76E56991-C964-444B-82A6-AFDA5145E18A}.Release.Build.0 = Release|Win32 {2011B7B6-6932-431D-83A3-E825A271F8A8}.Debug.ActiveCfg = Debug|Win32 {2011B7B6-6932-431D-83A3-E825A271F8A8}.Debug.Build.0 = Debug|Win32 {2011B7B6-6932-431D-83A3-E825A271F8A8}.Release.ActiveCfg = Release|Win32 {2011B7B6-6932-431D-83A3-E825A271F8A8}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection GlobalSection(ExtensibilityAddIns) = postSolution EndGlobalSection EndGlobal stund/udp.cxx0000644000175000017500000002115311710231326011321 0ustar kkkk#include #include #include #include #include #include #include #ifdef WIN32 #include #include #include #else #include #include #include #include #include #include #include #include #include #include #endif #include #include "udp.h" using namespace std; Socket openPort( unsigned short port, unsigned int interfaceIp, bool verbose ) { Socket fd; fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); if ( fd == INVALID_SOCKET ) { int err = getErrno(); cerr << "Could not create a UDP socket:" << err << endl; return INVALID_SOCKET; } struct sockaddr_in addr; memset((char*) &(addr),0, sizeof((addr))); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(port); if ( (interfaceIp != 0) && ( interfaceIp != 0x100007f ) ) { addr.sin_addr.s_addr = htonl(interfaceIp); if (verbose ) { clog << "Binding to interface " << hex << "0x" << htonl(interfaceIp) << dec << endl; } } if ( bind( fd,(struct sockaddr*)&addr, sizeof(addr)) != 0 ) { int e = getErrno(); switch (e) { case 0: { cerr << "Could not bind socket" << endl; return INVALID_SOCKET; } case EADDRINUSE: { cerr << "Port " << port << " for receiving UDP is in use" << endl; return INVALID_SOCKET; } break; case EADDRNOTAVAIL: { if ( verbose ) { cerr << "Cannot assign requested address" << endl; } return INVALID_SOCKET; } break; default: { cerr << "Could not bind UDP receive port" << "Error=" << e << " " << strerror(e) << endl; return INVALID_SOCKET; } break; } } if ( verbose ) { clog << "Opened port " << port << " with fd " << fd << endl; } assert( fd != INVALID_SOCKET ); return fd; } bool getMessage( Socket fd, char* buf, int* len, unsigned int* srcIp, unsigned short* srcPort, bool verbose) { assert( fd != INVALID_SOCKET ); int originalSize = *len; assert( originalSize > 0 ); struct sockaddr_in from; int fromLen = sizeof(from); *len = recvfrom(fd, buf, originalSize, 0, (struct sockaddr *)&from, (socklen_t*)&fromLen); if ( *len == SOCKET_ERROR ) { int err = getErrno(); switch (err) { case ENOTSOCK: cerr << "Error fd not a socket" << endl; break; case ECONNRESET: cerr << "Error connection reset - host not reachable" << endl; break; default: cerr << "Socket Error=" << err << endl; } return false; } if ( *len < 0 ) { clog << "socket closed? negative len" << endl; return false; } if ( *len == 0 ) { clog << "socket closed? zero len" << endl; return false; } *srcPort = ntohs(from.sin_port); *srcIp = ntohl(from.sin_addr.s_addr); if ( (*len)+1 >= originalSize ) { if (verbose) { clog << "Received a message that was too large" << endl; } return false; } buf[*len]=0; return true; } bool sendMessage( Socket fd, char* buf, int l, unsigned int dstIp, unsigned short dstPort, bool verbose) { assert( fd != INVALID_SOCKET ); int s; if ( dstPort == 0 ) { // sending on a connected port assert( dstIp == 0 ); s = send(fd,buf,l,0); } else { assert( dstIp != 0 ); assert( dstPort != 0 ); struct sockaddr_in to; int toLen = sizeof(to); memset(&to,0,toLen); to.sin_family = AF_INET; to.sin_port = htons(dstPort); to.sin_addr.s_addr = htonl(dstIp); s = sendto(fd, buf, l, 0,(sockaddr*)&to, toLen); } if ( s == SOCKET_ERROR ) { int e = getErrno(); switch (e) { case ECONNREFUSED: case EHOSTDOWN: case EHOSTUNREACH: { // quietly ignore this } break; case EAFNOSUPPORT: { cerr << "err EAFNOSUPPORT in send" << endl; } break; default: { cerr << "err " << e << " " << strerror(e) << " in send" << endl; } } return false; } if ( s == 0 ) { cerr << "no data sent in send" << endl; return false; } if ( s != l ) { if (verbose) { cerr << "only " << s << " out of " << l << " bytes sent" << endl; } return false; } return true; } void initNetwork() { #ifdef WIN32 WORD wVersionRequested = MAKEWORD( 2, 2 ); WSADATA wsaData; int err; err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { // could not find a usable WinSock DLL cerr << "Could not load winsock" << endl; assert(0); // is this is failing, try a different version that 2.2, 1.0 or later will likely work exit(1); } /* Confirm that the WinSock DLL supports 2.2.*/ /* Note that if the DLL supports versions greater */ /* than 2.2 in addition to 2.2, it will still return */ /* 2.2 in wVersion since that is the version we */ /* requested. */ if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 ) { /* Tell the user that we could not find a usable */ /* WinSock DLL. */ WSACleanup( ); cerr << "Bad winsock verion" << endl; assert(0); // is this is failing, try a different version that 2.2, 1.0 or later will likely work exit(1); } #endif } /* ==================================================================== * The Vovida Software License, Version 1.0 * * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The names "VOCAL", "Vovida Open Communication Application Library", * and "Vovida Open Communication Application Library (VOCAL)" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact vocal@vovida.org. * * 4. Products derived from this software may not be called "VOCAL", nor * may "VOCAL" appear in their name, without prior written * permission of Vovida Networks, Inc. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * * ==================================================================== * * This software consists of voluntary contributions made by Vovida * Networks, Inc. and many individuals on behalf of Vovida Networks, * Inc. For more information on Vovida Networks, Inc., please see * . * */ // Local Variables: // mode:c++ // c-file-style:"ellemtel" // c-file-offsets:((case-label . +)) // indent-tabs-mode:nil // End: stund/license.txt0000644000175000017500000000341611710231326012172 0ustar kkkkThe Vovida Software License, Version 1.0 Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. The names "VOCAL", "Vovida Open Communication Application Library", and "Vovida Open Communication Application Library (VOCAL)" must not be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact vocal@vovida.org. Products derived from this software may not be called "VOCAL", nor may "VOCAL" appear in their name, without prior written permission. THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DAMAGES IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. stund/server.sln0000644000175000017500000000157311710231326012035 0ustar kkkkMicrosoft Visual Studio Solution File, Format Version 7.00 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "server", "server.vcproj", "{2011B7B6-6932-431D-83A3-E825A271F8A8}" EndProject Global GlobalSection(SolutionConfiguration) = preSolution ConfigName.0 = Debug ConfigName.1 = Release EndGlobalSection GlobalSection(ProjectDependencies) = postSolution EndGlobalSection GlobalSection(ProjectConfiguration) = postSolution {2011B7B6-6932-431D-83A3-E825A271F8A8}.Debug.ActiveCfg = Debug|Win32 {2011B7B6-6932-431D-83A3-E825A271F8A8}.Debug.Build.0 = Debug|Win32 {2011B7B6-6932-431D-83A3-E825A271F8A8}.Release.ActiveCfg = Release|Win32 {2011B7B6-6932-431D-83A3-E825A271F8A8}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection GlobalSection(ExtensibilityAddIns) = postSolution EndGlobalSection EndGlobal stund/nattestwarning.txt0000644000175000017500000000414411710231326013617 0ustar kkkkWARNING: This script runs as "root" and makes changes to your network interface configuration. This script makes several assumptions about the test environment you might be using. Several of these assumptions may not hold in your environment and could cause you to lose all connectivity to this or other computers. It is designed to be run from the console on two networks which are connected only to a NAT in a configuration like the one shown below: Logical Configuration +--------+ | STUN |192.168.0.2 +-------+ | Client |---------------| | +--------+ | |public +--------+ | |side | STUN | 1.1.1.2 192.168.0.1 | NAT |------------| Server | 1.1.1.3 private side| |1.1.1.1 +--------+ | | +--------+ | | | STUN |---------------| | | Client |192.168.0.3 +-------+ +--------+ The test actually just requires a single computer with two interfaces which acts as a STUN server and a pair of cooperating STUN clients. The physical configuration is shown below. First plug in the NAT and computer and configure the primary IP interface on each interface. There should be no other computers or networks connected to the test bed. Physical Configuration Private Public or "inside" or "outside" interface +--------------+ interface | NAT device | 192.168.0.1 +-----| under |-----+ 1.1.1.1 | | test | | | | | | | +--------------+ | | | | | | +--------------+ | | | test | | 192.168.0.2 +-----| computer |-----+ 1.1.1.2 192.168.0.3 eth1| |eth0 1.1.1.3 | | +--------------+ stund/id.pem0000644000175000017500000000160311710231326011102 0ustar kkkk-----BEGIN CERTIFICATE----- MIICazCCAdQCAQMwDQYJKoZIhvcNAQEEBQAwgYAxCzAJBgNVBAYTAlVBMQswCQYD VQQIEwJDQTERMA8GA1UEBxMITWlscGl0YXMxDjAMBgNVBAoTBUZvb0NvMRMwEQYD VQQLEwp3aWRnZXQgZGl2MRIwEAYDVQQDEwlsb2NhbGhvc3QxGDAWBgkqhkiG9w0B CQEWCWZvb0Bmb28uYzAeFw0wMjExMDEwMzUyMjhaFw0wMjEyMDEwMzUyMjhaMHsx CzAJBgNVBAYTAkdCMRIwEAYDVQQIEwlCZXJrc2hpcmUxEDAOBgNVBAcTB05ld2J1 cnkxFzAVBgNVBAoTDk15IENvbXBhbnkgTHRkMRIwEAYDVQQDEwlsb2NhbGhvc3Qx GTAXBgkqhkiG9w0BCQEWCnNlcnZlci5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0A MIGJAoGBAO0DwcHArwHx2XoX3XAcjc9lc/ERveDqFO9NJChtA2R3/b7EaH4FOlv1 QxL5aaCxiwhqHVo7F/BG2OxcIIBCp8HBLRYwmKnWwta4s4imD3ZI/AAaTPm5r/KJ GbAh0vpF7WIdtsEOaSYbnLVnQTXTgfswgoH502sM13fVY0qJhjrTAgMBAAEwDQYJ KoZIhvcNAQEEBQADgYEAUSwhHT7j9ammZBo/VHT8mZylqOzBakMuASiUQNwL40sc 0eb3MtKEg2GLlX8GtB0g2+bieA337XSXe4kyhpQ7j9ClajI3Dpr463ZKLJ43JFH0 Ynqkfo61d9fQYtxJTXjYIatzLNXpzsxADEQ2MGokQmEMGJcBftLdMfvtOy8Kh7I= -----END CERTIFICATE----- stund/id_key.pem0000644000175000017500000000156711710231326011763 0ustar kkkk-----BEGIN RSA PRIVATE KEY----- MIICXQIBAAKBgQDtA8HBwK8B8dl6F91wHI3PZXPxEb3g6hTvTSQobQNkd/2+xGh+ BTpb9UMS+WmgsYsIah1aOxfwRtjsXCCAQqfBwS0WMJip1sLWuLOIpg92SPwAGkz5 ua/yiRmwIdL6Re1iHbbBDmkmG5y1Z0E104H7MIKB+dNrDNd31WNKiYY60wIDAQAB AoGAJt7C2/+5s9vyCq/3RPep2iWNSi/asBQzsrs3/tlCASwclTio2mIJHCOxCF+X Dx+O6aZdgfrHBkTYNos1WVOVJ0S3K47HQ5gPZgIus855SEmfINzJkTPz0kahjUj9 hMeKfmtM6uRqkVcs+H35chhXg2rW0uQRP3tlgd5wq+uRjoECQQD30oykMIbA32i6 nHw1u1zJNZXaABoUsXlu5ylwXZp39FYxQiMmwTzI7AJAKTCf2YiHP4C9YLKnjKMo 8D+HudAxAkEA9NXo91TuOYtxYn3NJi4FCpo+hcrHH33M+ttB8L+lO9ctgzGuvI63 pNszIVTNnV+RwnSyR+CtO7q/PQOcrK8eQwJAVCXVBYdIqkLxv7OU5XXKKrQcPtqc AHzGm+a4BmRyJ9r6TV2ErAsfRaYFmZ2i2hQ2LJ5ea29jGktBt4vkNoTccQJBAL49 dE6ybITEJ+8axwwSmBI79bbp8D0099A4DA2wLAjKUu/s69RRpLpxJFKS3U2aE90f 5eNZ3eFaYvxa0SOQ0pcCQQDEaX+MPPNUlOk4Im7XTaiT/qQDJyIHyl7+UeHOZbvN X9HHnTnImOk38K3zFpEvCF9LHR3BTUzVcOEIPR/3hTor -----END RSA PRIVATE KEY----- stund/stun.h0000644000175000017500000002473711710231326011162 0ustar kkkk#ifndef STUN_H #define STUN_H #include #include // if you change this version, change in makefile too #define STUN_VERSION "0.97" #define STUN_MAX_STRING 256 #define STUN_MAX_UNKNOWN_ATTRIBUTES 8 #define STUN_MAX_MESSAGE_SIZE 2048 #define STUN_PORT 3478 // define some basic types typedef unsigned char UInt8; typedef unsigned short UInt16; typedef unsigned int UInt32; #if defined( WIN32 ) typedef unsigned __int64 UInt64; #else typedef unsigned long long UInt64; #endif typedef struct { unsigned char octet[16]; } UInt128; /// define a structure to hold a stun address const UInt8 IPv4Family = 0x01; const UInt8 IPv6Family = 0x02; // define flags const UInt32 ChangeIpFlag = 0x04; const UInt32 ChangePortFlag = 0x02; // define stun attribute 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; // Non standard extention // define types for a stun message const UInt16 BindRequestMsg = 0x0001; const UInt16 BindResponseMsg = 0x0101; const UInt16 BindErrorResponseMsg = 0x0111; const UInt16 SharedSecretRequestMsg = 0x0002; const UInt16 SharedSecretResponseMsg = 0x0102; const UInt16 SharedSecretErrorResponseMsg = 0x0112; typedef struct { UInt16 msgType; UInt16 msgLength; UInt128 id; } StunMsgHdr; typedef struct { UInt16 type; UInt16 length; } StunAtrHdr; typedef struct { UInt16 port; UInt32 addr; } StunAddress4; typedef struct { UInt8 pad; UInt8 family; StunAddress4 ipv4; } StunAtrAddress4; typedef struct { UInt32 value; } StunAtrChangeRequest; typedef struct { UInt16 pad; // all 0 UInt8 errorClass; UInt8 number; char reason[STUN_MAX_STRING]; UInt16 sizeReason; } StunAtrError; typedef struct { UInt16 attrType[STUN_MAX_UNKNOWN_ATTRIBUTES]; UInt16 numAttributes; } StunAtrUnknown; typedef struct { char value[STUN_MAX_STRING]; UInt16 sizeValue; } StunAtrString; typedef struct { char hash[20]; } StunAtrIntegrity; typedef enum { HmacUnkown=0, HmacOK, HmacBadUserName, HmacUnkownUserName, HmacFailed, } StunHmacStatus; typedef struct { StunMsgHdr msgHdr; bool hasMappedAddress; StunAtrAddress4 mappedAddress; bool hasResponseAddress; StunAtrAddress4 responseAddress; bool hasChangeRequest; StunAtrChangeRequest changeRequest; bool hasSourceAddress; StunAtrAddress4 sourceAddress; bool hasChangedAddress; StunAtrAddress4 changedAddress; bool hasUsername; StunAtrString username; bool hasPassword; StunAtrString password; bool hasMessageIntegrity; StunAtrIntegrity messageIntegrity; bool hasErrorCode; StunAtrError errorCode; bool hasUnknownAttributes; StunAtrUnknown unknownAttributes; bool hasReflectedFrom; StunAtrAddress4 reflectedFrom; bool hasXorMappedAddress; StunAtrAddress4 xorMappedAddress; bool xorOnly; bool hasServerName; StunAtrString serverName; bool hasSecondaryAddress; StunAtrAddress4 secondaryAddress; } StunMessage; // Define enum with different types of NAT typedef enum { StunTypeUnknown=0, StunTypeFailure, StunTypeOpen, StunTypeBlocked, StunTypeIndependentFilter, StunTypeDependentFilter, StunTypePortDependedFilter, StunTypeDependentMapping, //StunTypeConeNat, //StunTypeRestrictedNat, //StunTypePortRestrictedNat, //StunTypeSymNat, StunTypeFirewall, } NatType; #ifdef WIN32 typedef SOCKET Socket; #else typedef int Socket; #endif #define MAX_MEDIA_RELAYS 500 #define MAX_RTP_MSG_SIZE 1500 #define MEDIA_RELAY_TIMEOUT 3*60 typedef struct { int relayPort; // media relay port int fd; // media relay file descriptor StunAddress4 destination; // NAT IP:port time_t expireTime; // if no activity after time, close the socket } StunMediaRelay; typedef struct { StunAddress4 myAddr; StunAddress4 altAddr; Socket myFd; Socket altPortFd; Socket altIpFd; Socket altIpPortFd; bool relay; // true if media relaying is to be done StunMediaRelay relays[MAX_MEDIA_RELAYS]; } StunServerInfo; 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(); /// find the IP address of a the specified stun server - return false is fails parse bool stunParseServerName( char* serverName, StunAddress4& stunServerAddr); bool stunParseHostName( char* peerName, UInt32& ip, UInt16& portVal, UInt16 defaultPort ); /// return true if all is OK /// Create a media relay and do the STERN thing if startMediaPort is non-zero bool stunInitServer(StunServerInfo& info, const StunAddress4& myAddr, const StunAddress4& altAddr, int startMediaPort, bool verbose); void stunStopServer(StunServerInfo& info); /// return true if all is OK bool stunServerProcess(StunServerInfo& info, bool verbose); /// returns number of address found - take array or addres int stunFindLocalInterfaces(UInt32* addresses, int maxSize ); void stunTest( StunAddress4& dest, int testNum, bool verbose, StunAddress4* srcAddr=0 ); NatType stunNatType( StunAddress4& dest, bool verbose, bool* preservePort=0, // if set, is return for if NAT preservers ports or not bool* hairpin=0 , // if set, is the return for if NAT will hairpin packets int port=0, // port to use for the test, 0 to choose random port StunAddress4* sAddr=0 // NIC to use ); /// prints a StunAddress std::ostream& operator<<( std::ostream& strm, const StunAddress4& addr); 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(); #endif /* ==================================================================== * The Vovida Software License, Version 1.0 * * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The names "VOCAL", "Vovida Open Communication Application Library", * and "Vovida Open Communication Application Library (VOCAL)" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact vocal@vovida.org. * * 4. Products derived from this software may not be called "VOCAL", nor * may "VOCAL" appear in their name, without prior written * permission of Vovida Networks, Inc. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * * ==================================================================== * * This software consists of voluntary contributions made by Vovida * Networks, Inc. and many individuals on behalf of Vovida Networks, * Inc. For more information on Vovida Networks, Inc., please see * . * */ // Local Variables: // mode:c++ // c-file-style:"ellemtel" // c-file-offsets:((case-label . +)) // indent-tabs-mode:nil // End: stund/readme.txt0000644000175000017500000000140411710231326012000 0ustar kkkkRunning the STUN server: ------------------------ You need to have 2 IP addresses next to each other to run the STUN server. ./server -h primary-ip -a secondary-ip -b STUN server version 0.97 Usage: ./server [-v] [-h] [-h IP_Address] [-a IP_Address] [-p port] [-o port] [-m mediaport] If the IP addresses of your NIC are 10.0.1.150 and 10.0.1.151, run this program with ./server -v -h 10.0.1.150 -a 10.0.1.151 STUN servers need two IP addresses and two ports, these can be specified with: -h sets the primary IP -a sets the secondary IP -p sets the primary port and defaults to 3478 -o sets the secondary port and defaults to 3479 -b makes the program run in the backgroud -m sets up a STERN server starting at port m -v runs in verbose mode stund/server.vcproj0000644000175000017500000000611011710231326012534 0ustar kkkk stund/Makefile0000644000175000017500000000256511710231326011453 0ustar kkkk TARS= client.cxx server.cxx stun.cxx stun.h tlsServer.cxx udp.cxx udp.h \ Makefile rfc3489.txt\ client.sln client.vcproj server.sln server.vcproj Stun.sln \ id.pem id_key.pem root.pem \ nattestwarning.txt nattest wnattest.bat \ WinStun/resource.h WinStun/stdafx.cpp WinStun/stdafx.h \ WinStun/WinStun.cpp WinStun/WinStunDlg.cpp WinStun/WinStunDlg.h WinStun/WinStun.h \ WinStun/WinStun.rc WinStun/WinStun.vcproj \ WinStun/res/WinStun.ico WinStun/res/WinStun.manifest WinStun/res/WinStun.rc2 \ WinStunSetup/WinStunSetup.vdproj # if you chnage this version, change in stun.h too VERSION=0.96 #CXXFLAGS+=-O2 #LDFLAGS+=-O2 -lssl STUNLIB=libstun.a # # Alternatively, for debugging. # CXXFLAGS+=-g -O -Wall LDFLAGS+=-g -O -Wall # for solaris #LDFLAGS+= -lnsl -lsocket all: server client clean: - rm *.o server client tlsServer tar: $(TARS) cd ..; tar cvfz `date +"stund/stund_$(VERSION)_$(PROG)%b%d.tgz"` \ $(addprefix stund/, $(TARS)) server: server.o stun.o udp.o $(CXX) $(LDFLAGS) -o $@ $^ tlsServer: tlsServer.o stun.o udp.o $(CXX) $(LDFLAGS) -o $@ $^ client: client.o stun.o udp.o $(CXX) $(LDFLAGS) -o $@ $^ %.o:%.cxx $(CXX) -c $(CPPFLAGS) $(CXXFLAGS) $< -o $@ libstun.a: stun.o udp.o ar rv $@ $< %:RCS/% co $@ # Dependancies server.o: stun.h udp.h client.o: stun.h udp.h stun.o: stun.h udp.h udp.o: stun.h udp.h tlsServer.o: stun.h udp.h stund/client.vcproj0000644000175000017500000000611011710231326012504 0ustar kkkk stund/stun.cxx0000644000175000017500000020242211710231326011522 0ustar kkkk#include #include #include #include #include #ifdef WIN32 #include #include #include #include #else #include #include #include #include #include #include #include #include #include #include #include #include #include #include #endif #if defined(__sparc__) || defined(WIN32) #define NOSSL #endif #define NOSSL #include "udp.h" #include "stun.h" using namespace std; 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 ) { if ( hdrLen != 8 ) { clog << "hdrLen wrong for Address" <= sizeof(result) ) { clog << "head on Error too large" << endl; return false; } else { memcpy(&result.pad, body, 2); body+=2; result.pad = ntohs(result.pad); result.errorClass = *body++; result.number = *body++; result.sizeReason = hdrLen - 4; memcpy(&result.reason, body, result.sizeReason); result.reason[result.sizeReason] = 0; return true; } } static bool stunParseAtrUnknown( char* body, unsigned int hdrLen, StunAtrUnknown& result ) { if ( hdrLen >= sizeof(result) ) { return false; } else { if (hdrLen % 4 != 0) return false; result.numAttributes = hdrLen / 4; for (int i=0; i= STUN_MAX_STRING ) { clog << "String is too large" << endl; return false; } else { if (hdrLen % 4 != 0) { clog << "Bad length string " << hdrLen << endl; return false; } result.sizeValue = hdrLen; memcpy(&result.value, body, hdrLen); result.value[hdrLen] = 0; return true; } } static bool stunParseAtrIntegrity( char* body, unsigned int hdrLen, StunAtrIntegrity& result ) { if ( hdrLen != 20) { clog << "MessageIntegrity must be 20 bytes" << endl; return false; } else { memcpy(&result.hash, body, hdrLen); return true; } } bool stunParseMessage( char* buf, unsigned int bufLen, StunMessage& msg, bool verbose) { if (verbose) clog << "Received stun message: " << bufLen << " bytes" << endl; memset(&msg, 0, sizeof(msg)); if (sizeof(StunMsgHdr) > bufLen) { clog << "Bad message" << endl; return false; } memcpy(&msg.msgHdr, buf, sizeof(StunMsgHdr)); msg.msgHdr.msgType = ntohs(msg.msgHdr.msgType); msg.msgHdr.msgLength = ntohs(msg.msgHdr.msgLength); if (msg.msgHdr.msgLength + sizeof(StunMsgHdr) != bufLen) { clog << "Message header length doesn't match message size: " << msg.msgHdr.msgLength << " - " << bufLen << endl; return false; } char* body = buf + sizeof(StunMsgHdr); unsigned int size = msg.msgHdr.msgLength; //clog << "bytes after header = " << size << endl; while ( size > 0 ) { // !jf! should check that there are enough bytes left in the buffer StunAtrHdr* attr = reinterpret_cast(body); unsigned int attrLen = ntohs(attr->length); int atrType = ntohs(attr->type); //if (verbose) clog << "Found attribute type=" << AttrNames[atrType] << " length=" << attrLen << endl; if ( attrLen+4 > size ) { clog << "claims attribute is larger than size of message " <<"(attribute type="<(&ndata), sizeof(UInt16)); return buf + sizeof(UInt16); } static char* encode32(char* buf, UInt32 data) { UInt32 ndata = htonl(data); memcpy(buf, reinterpret_cast(&ndata), sizeof(UInt32)); return buf + sizeof(UInt32); } static char* encode(char* buf, const char* data, unsigned int length) { memcpy(buf, data, length); return buf + length; } static char* encodeAtrAddress4(char* ptr, UInt16 type, const StunAtrAddress4& atr) { ptr = encode16(ptr, type); ptr = encode16(ptr, 8); *ptr++ = atr.pad; *ptr++ = IPv4Family; ptr = encode16(ptr, atr.ipv4.port); ptr = encode32(ptr, atr.ipv4.addr); return ptr; } static char* encodeAtrChangeRequest(char* ptr, const StunAtrChangeRequest& atr) { ptr = encode16(ptr, ChangeRequest); ptr = encode16(ptr, 4); ptr = encode32(ptr, atr.value); return ptr; } static char* encodeAtrError(char* ptr, const StunAtrError& atr) { ptr = encode16(ptr, ErrorCode); ptr = encode16(ptr, 6 + atr.sizeReason); ptr = encode16(ptr, atr.pad); *ptr++ = atr.errorClass; *ptr++ = atr.number; ptr = encode(ptr, atr.reason, atr.sizeReason); return ptr; } static char* encodeAtrUnknown(char* ptr, const StunAtrUnknown& atr) { ptr = encode16(ptr, UnknownAttribute); ptr = encode16(ptr, 2+2*atr.numAttributes); for (int i=0; i= sizeof(StunMsgHdr)); char* ptr = buf; ptr = encode16(ptr, msg.msgHdr.msgType); char* lengthp = ptr; ptr = encode16(ptr, 0); ptr = encode(ptr, reinterpret_cast(msg.msgHdr.id.octet), sizeof(msg.msgHdr.id)); if (verbose) clog << "Encoding stun message: " << endl; if (msg.hasMappedAddress) { if (verbose) clog << "Encoding MappedAddress: " << msg.mappedAddress.ipv4 << endl; ptr = encodeAtrAddress4 (ptr, MappedAddress, msg.mappedAddress); } if (msg.hasResponseAddress) { if (verbose) clog << "Encoding ResponseAddress: " << msg.responseAddress.ipv4 << endl; ptr = encodeAtrAddress4(ptr, ResponseAddress, msg.responseAddress); } if (msg.hasChangeRequest) { if (verbose) clog << "Encoding ChangeRequest: " << msg.changeRequest.value << endl; ptr = encodeAtrChangeRequest(ptr, msg.changeRequest); } if (msg.hasSourceAddress) { if (verbose) clog << "Encoding SourceAddress: " << msg.sourceAddress.ipv4 << endl; ptr = encodeAtrAddress4(ptr, SourceAddress, msg.sourceAddress); } if (msg.hasChangedAddress) { if (verbose) clog << "Encoding ChangedAddress: " << msg.changedAddress.ipv4 << endl; ptr = encodeAtrAddress4(ptr, ChangedAddress, msg.changedAddress); } if (msg.hasUsername) { if (verbose) clog << "Encoding Username: " << msg.username.value << endl; ptr = encodeAtrString(ptr, Username, msg.username); } if (msg.hasPassword) { if (verbose) clog << "Encoding Password: " << msg.password.value << endl; ptr = encodeAtrString(ptr, Password, msg.password); } if (msg.hasErrorCode) { if (verbose) clog << "Encoding ErrorCode: class=" << int(msg.errorCode.errorClass) << " number=" << int(msg.errorCode.number) << " reason=" << msg.errorCode.reason << endl; ptr = encodeAtrError(ptr, msg.errorCode); } if (msg.hasUnknownAttributes) { if (verbose) clog << "Encoding UnknownAttribute: ???" << endl; ptr = encodeAtrUnknown(ptr, msg.unknownAttributes); } if (msg.hasReflectedFrom) { if (verbose) clog << "Encoding ReflectedFrom: " << msg.reflectedFrom.ipv4 << endl; ptr = encodeAtrAddress4(ptr, ReflectedFrom, msg.reflectedFrom); } if (msg.hasXorMappedAddress) { if (verbose) clog << "Encoding XorMappedAddress: " << msg.xorMappedAddress.ipv4 << endl; ptr = encodeAtrAddress4 (ptr, XorMappedAddress, msg.xorMappedAddress); } if (msg.xorOnly) { if (verbose) clog << "Encoding xorOnly: " << endl; ptr = encodeXorOnly( ptr ); } if (msg.hasServerName) { if (verbose) clog << "Encoding ServerName: " << msg.serverName.value << endl; ptr = encodeAtrString(ptr, ServerName, msg.serverName); } if (msg.hasSecondaryAddress) { if (verbose) clog << "Encoding SecondaryAddress: " << msg.secondaryAddress.ipv4 << endl; ptr = encodeAtrAddress4 (ptr, SecondaryAddress, msg.secondaryAddress); } if (password.sizeValue > 0) { if (verbose) clog << "HMAC with password: " << password.value << endl; StunAtrIntegrity integrity; computeHmac(integrity.hash, buf, int(ptr-buf) , password.value, password.sizeValue); ptr = encodeAtrIntegrity(ptr, integrity); } if (verbose) clog << endl; encode16(lengthp, UInt16(ptr - buf - sizeof(StunMsgHdr))); return int(ptr - buf); } int stunRand() { // return 32 bits of random stuff assert( sizeof(int) == 4 ); static bool init=false; if ( !init ) { init = true; UInt64 tick; #if defined(WIN32) volatile unsigned int lowtick=0,hightick=0; __asm { rdtsc mov lowtick, eax mov hightick, edx } tick = hightick; tick <<= 32; tick |= lowtick; #elif defined(__GNUC__) && ( defined(__i686__) || defined(__i386__) ) asm("rdtsc" : "=A" (tick)); #elif defined (__SUNPRO_CC) || defined( __sparc__ ) tick = gethrtime(); #elif defined(__MACH__) || defined(__linux) int fd=open("/dev/random",O_RDONLY); read(fd,&tick,sizeof(tick)); closesocket(fd); #else # error Need some way to seed the random number generator #endif int seed = int(tick); #ifdef WIN32 srand(seed); #else srandom(seed); #endif } #ifdef WIN32 assert( RAND_MAX == 0x7fff ); int r1 = rand(); int r2 = rand(); int ret = (r1<<16) + r2; return ret; #else return random(); #endif } /// return a random number to use as a port int stunRandomPort() { int min=0x4000; int max=0x7FFF; int ret = stunRand(); ret = ret|min; ret = ret&max; return ret; } #ifdef NOSSL static void computeHmac(char* hmac, const char* input, int length, const char* key, int sizeKey) { strncpy(hmac,"hmac-not-implemented",20); } #else #include static void computeHmac(char* hmac, const char* input, int length, const char* key, int sizeKey) { unsigned int resultSize=0; HMAC(EVP_sha1(), key, sizeKey, reinterpret_cast(input), length, reinterpret_cast(hmac), &resultSize); assert(resultSize == 20); } #endif static void toHex(const char* buffer, int bufferSize, char* output) { static char hexmap[] = "0123456789abcdef"; const char* p = buffer; char* r = output; for (int i=0; i < bufferSize; i++) { unsigned char temp = *p++; int hi = (temp & 0xf0)>>4; int low = (temp & 0xf); *r++ = hexmap[hi]; *r++ = hexmap[low]; } *r = 0; } void stunCreateUserName(const StunAddress4& source, StunAtrString* username) { UInt64 time = stunGetSystemTimeSecs(); time -= (time % 20*60); //UInt64 hitime = time >> 32; UInt64 lotime = time & 0xFFFFFFFF; char buffer[1024]; sprintf(buffer, "%08x:%08x:%08x:", UInt32(source.addr), UInt32(stunRand()), UInt32(lotime)); assert( strlen(buffer) < 1024 ); assert(strlen(buffer) + 41 < STUN_MAX_STRING); char hmac[20]; char key[] = "Jason"; computeHmac(hmac, buffer, strlen(buffer), key, strlen(key) ); char hmacHex[41]; toHex(hmac, 20, hmacHex ); hmacHex[40] =0; strcat(buffer,hmacHex); int l = strlen(buffer); assert( l+1 < STUN_MAX_STRING ); assert( l%4 == 0 ); username->sizeValue = l; memcpy(username->value,buffer,l); username->value[l]=0; //if (verbose) clog << "computed username=" << username.value << endl; } void stunCreatePassword(const StunAtrString& username, StunAtrString* password) { char hmac[20]; char key[] = "Fluffy"; //char buffer[STUN_MAX_STRING]; computeHmac(hmac, username.value, strlen(username.value), key, strlen(key)); toHex(hmac, 20, password->value); password->sizeValue = 40; password->value[40]=0; //clog << "password=" << password->value << endl; } UInt64 stunGetSystemTimeSecs() { UInt64 time=0; #if defined(WIN32) SYSTEMTIME t; // CJ TODO - this probably has bug on wrap around every 24 hours GetSystemTime( &t ); time = (t.wHour*60+t.wMinute)*60+t.wSecond; #else struct timeval now; gettimeofday( &now , NULL ); //assert( now ); time = now.tv_sec; #endif return time; } ostream& operator<< ( ostream& strm, const UInt128& r ) { strm << int(r.octet[0]); for ( int i=1; i<16; i++ ) { strm << ':' << int(r.octet[i]); } return strm; } ostream& operator<<( ostream& strm, const StunAddress4& addr) { UInt32 ip = addr.addr; strm << ((int)(ip>>24)&0xFF) << "."; strm << ((int)(ip>>16)&0xFF) << "."; strm << ((int)(ip>> 8)&0xFF) << "."; strm << ((int)(ip>> 0)&0xFF) ; strm << ":" << addr.port; return strm; } // returns true if it scucceeded bool stunParseHostName( char* peerName, UInt32& ip, UInt16& portVal, UInt16 defaultPort ) { in_addr sin_addr; char host[512]; strncpy(host,peerName,512); host[512-1]='\0'; char* port = NULL; int portNum = defaultPort; // pull out the port part if present. char* sep = strchr(host,':'); if ( sep == NULL ) { portNum = defaultPort; } else { *sep = '\0'; port = sep + 1; // set port part char* endPtr=NULL; portNum = strtol(port,&endPtr,10); if ( endPtr != NULL ) { if ( *endPtr != '\0' ) { portNum = defaultPort; } } } if ( portNum < 1024 ) return false; if ( portNum >= 0xFFFF ) return false; // figure out the host part struct hostent* h; #ifdef WIN32 assert( strlen(host) >= 1 ); if ( isdigit( host[0] ) ) { // assume it is a ip address unsigned long a = inet_addr(host); //cerr << "a=0x" << hex << a << dec << endl; ip = ntohl( a ); } else { // assume it is a host name h = gethostbyname( host ); if ( h == NULL ) { int err = getErrno(); std::cerr << "error was " << err << std::endl; assert( err != WSANOTINITIALISED ); ip = ntohl( 0x7F000001L ); return false; } else { sin_addr = *(struct in_addr*)h->h_addr; ip = ntohl( sin_addr.s_addr ); } } #else h = gethostbyname( host ); if ( h == NULL ) { int err = getErrno(); std::cerr << "error was " << err << std::endl; ip = ntohl( 0x7F000001L ); return false; } else { sin_addr = *(struct in_addr*)h->h_addr; ip = ntohl( sin_addr.s_addr ); } #endif portVal = portNum; return true; } bool stunParseServerName( char* name, StunAddress4& addr) { assert(name); // TODO - put in DNS SRV stuff. bool ret = stunParseHostName( name, addr.addr, addr.port, 3478); if ( ret != true ) { addr.port=0xFFFF; } return ret; } static void stunCreateErrorResponse(StunMessage& response, int cl, int number, const char* msg) { response.msgHdr.msgType = BindErrorResponseMsg; response.hasErrorCode = true; response.errorCode.errorClass = cl; response.errorCode.number = number; strcpy(response.errorCode.reason, msg); } #if 0 static void stunCreateSharedSecretErrorResponse(StunMessage& response, int cl, int number, const char* msg) { response.msgHdr.msgType = SharedSecretErrorResponseMsg; response.hasErrorCode = true; response.errorCode.errorClass = cl; response.errorCode.number = number; strcpy(response.errorCode.reason, msg); } #endif static void stunCreateSharedSecretResponse(const StunMessage& request, const StunAddress4& source, StunMessage& response) { response.msgHdr.msgType = SharedSecretResponseMsg; response.msgHdr.id = request.msgHdr.id; response.hasUsername = true; stunCreateUserName( source, &response.username); response.hasPassword = true; stunCreatePassword( response.username, &response.password); } // This funtion takes a single message sent to a stun server, parses // and constructs an apropriate repsonse - returns true if message is // valid 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) { // set up information for default response memset( resp, 0 , sizeof(*resp) ); *changeIp = false; *changePort = false; StunMessage req; bool ok = stunParseMessage( buf,bufLen, req, verbose); if (!ok) // Complete garbage, drop it on the floor { if (verbose) clog << "Request did not parse" << endl; return false; } if (verbose) clog << "Request parsed ok" << endl; StunAddress4 mapped = req.mappedAddress.ipv4; StunAddress4 respondTo = req.responseAddress.ipv4; UInt32 flags = req.changeRequest.value; switch (req.msgHdr.msgType) { case SharedSecretRequestMsg: if(verbose) clog << "Received SharedSecretRequestMsg on udp. send error 433." << endl; // !cj! - should fix so you know if this came over TLS or UDP stunCreateSharedSecretResponse(req, from, *resp); //stunCreateSharedSecretErrorResponse(*resp, 4, 33, "this request must be over TLS"); return true; case BindRequestMsg: if (!req.hasMessageIntegrity) { if (verbose) clog << "BindRequest does not contain MessageIntegrity" << endl; if (0) // !jf! mustAuthenticate { if(verbose) clog << "Received BindRequest with no MessageIntegrity. Sending 401." << endl; stunCreateErrorResponse(*resp, 4, 1, "Missing MessageIntegrity"); return true; } } else { if (!req.hasUsername) { if (verbose) clog << "No UserName. Send 432." << endl; stunCreateErrorResponse(*resp, 4, 32, "No UserName and contains MessageIntegrity"); return true; } else { if (verbose) clog << "Validating username: " << req.username.value << endl; // !jf! could retrieve associated password from provisioning here if (strcmp(req.username.value, "test") == 0) { if (0) { // !jf! if the credentials are stale stunCreateErrorResponse(*resp, 4, 30, "Stale credentials on BindRequest"); return true; } else { if (verbose) clog << "Validating MessageIntegrity" << endl; // need access to shared secret unsigned char hmac[20]; #ifndef NOSSL unsigned int hmacSize=20; HMAC(EVP_sha1(), "1234", 4, reinterpret_cast(buf), bufLen-20-4, hmac, &hmacSize); assert(hmacSize == 20); #endif if (memcmp(buf, hmac, 20) != 0) { if (verbose) clog << "MessageIntegrity is bad. Sending " << endl; stunCreateErrorResponse(*resp, 4, 3, "Unknown username. Try test with password 1234"); return true; } // need to compute this later after message is filled in resp->hasMessageIntegrity = true; assert(req.hasUsername); resp->hasUsername = true; resp->username = req.username; // copy username in } } else { if (verbose) clog << "Invalid username: " << req.username.value << "Send 430." << endl; } } } // TODO !jf! should check for unknown attributes here and send 420 listing the // unknown attributes. if ( respondTo.port == 0 ) respondTo = from; if ( mapped.port == 0 ) mapped = from; *changeIp = ( flags & ChangeIpFlag )?true:false; *changePort = ( flags & ChangePortFlag )?true:false; if (verbose) { clog << "Request is valid:" << endl; clog << "\t flags=" << flags << endl; clog << "\t changeIp=" << *changeIp << endl; clog << "\t changePort=" << *changePort << endl; clog << "\t from = " << from << endl; clog << "\t respond to = " << respondTo << endl; clog << "\t mapped = " << mapped << endl; } // form the outgoing message resp->msgHdr.msgType = BindResponseMsg; for ( int i=0; i<16; i++ ) { resp->msgHdr.id.octet[i] = req.msgHdr.id.octet[i]; } if ( req.xorOnly == false ) { resp->hasMappedAddress = true; resp->mappedAddress.ipv4.port = mapped.port; resp->mappedAddress.ipv4.addr = mapped.addr; } if (1) // do xorMapped address or not { resp->hasXorMappedAddress = true; UInt16 id16 = req.msgHdr.id.octet[0]<<8 | req.msgHdr.id.octet[1]; UInt32 id32 = req.msgHdr.id.octet[0]<<24 | req.msgHdr.id.octet[1]<<16 | req.msgHdr.id.octet[2]<<8 | req.msgHdr.id.octet[3]; resp->xorMappedAddress.ipv4.port = mapped.port^id16; resp->xorMappedAddress.ipv4.addr = mapped.addr^id32; } resp->hasSourceAddress = true; resp->sourceAddress.ipv4.port = (*changePort) ? altAddr.port : myAddr.port; resp->sourceAddress.ipv4.addr = (*changeIp) ? altAddr.addr : myAddr.addr; resp->hasChangedAddress = true; resp->changedAddress.ipv4.port = altAddr.port; resp->changedAddress.ipv4.addr = altAddr.addr; if ( secondary.port != 0 ) { resp->hasSecondaryAddress = true; resp->secondaryAddress.ipv4.port = secondary.port; resp->secondaryAddress.ipv4.addr = secondary.addr; } if ( req.hasUsername && req.username.sizeValue > 0 ) { // copy username in resp->hasUsername = true; assert( req.username.sizeValue % 4 == 0 ); assert( req.username.sizeValue < STUN_MAX_STRING ); memcpy( resp->username.value, req.username.value, req.username.sizeValue ); resp->username.sizeValue = req.username.sizeValue; } if (1) // add ServerName { resp->hasServerName = true; const char serverName[] = "Vovida.org " STUN_VERSION; // must pad to mult of 4 assert( sizeof(serverName) < STUN_MAX_STRING ); //cerr << "sizeof serverName is " << sizeof(serverName) << endl; assert( sizeof(serverName)%4 == 0 ); memcpy( resp->serverName.value, serverName, sizeof(serverName)); resp->serverName.sizeValue = sizeof(serverName); } if ( req.hasMessageIntegrity & req.hasUsername ) { // this creates the password that will be used in the HMAC when then // messages is sent stunCreatePassword( req.username, hmacPassword ); } if (req.hasUsername && (req.username.sizeValue > 64 ) ) { UInt32 source; assert( sizeof(int) == sizeof(UInt32) ); sscanf(req.username.value, "%x", &source); resp->hasReflectedFrom = true; resp->reflectedFrom.ipv4.port = 0; resp->reflectedFrom.ipv4.addr = source; } destination->port = respondTo.port; destination->addr = respondTo.addr; return true; default: if (verbose) clog << "Unknown or unsupported request " << endl; return false; } assert(0); return false; } bool stunInitServer(StunServerInfo& info, const StunAddress4& myAddr, const StunAddress4& altAddr, int startMediaPort, bool verbose ) { assert( myAddr.port != 0 ); assert( altAddr.port!= 0 ); assert( myAddr.addr != 0 ); //assert( altAddr.addr != 0 ); info.myAddr = myAddr; info.altAddr = altAddr; info.myFd = INVALID_SOCKET; info.altPortFd = INVALID_SOCKET; info.altIpFd = INVALID_SOCKET; info.altIpPortFd = INVALID_SOCKET; memset(info.relays, 0, sizeof(info.relays)); if (startMediaPort > 0) { info.relay = true; for (int i=0; irelayPort = startMediaPort+i; relay->fd = 0; relay->expireTime = 0; } } else { info.relay = false; } if ((info.myFd = openPort(myAddr.port, myAddr.addr,verbose)) == INVALID_SOCKET) { clog << "Can't open " << myAddr << endl; stunStopServer(info); return false; } //if (verbose) clog << "Opened " << myAddr.addr << ":" << myAddr.port << " --> " << info.myFd << endl; if ((info.altPortFd = openPort(altAddr.port,myAddr.addr,verbose)) == INVALID_SOCKET) { clog << "Can't open " << myAddr << endl; stunStopServer(info); return false; } //if (verbose) clog << "Opened " << myAddr.addr << ":" << altAddr.port << " --> " << info.altPortFd << endl; info.altIpFd = INVALID_SOCKET; if ( altAddr.addr != 0 ) { if ((info.altIpFd = openPort( myAddr.port, altAddr.addr,verbose)) == INVALID_SOCKET) { clog << "Can't open " << altAddr << endl; stunStopServer(info); return false; } //if (verbose) clog << "Opened " << altAddr.addr << ":" << myAddr.port << " --> " << info.altIpFd << endl;; } info.altIpPortFd = INVALID_SOCKET; if ( altAddr.addr != 0 ) { if ((info.altIpPortFd = openPort(altAddr.port, altAddr.addr,verbose)) == INVALID_SOCKET) { clog << "Can't open " << altAddr << endl; stunStopServer(info); return false; } //if (verbose) clog << "Opened " << altAddr.addr << ":" << altAddr.port << " --> " << info.altIpPortFd << endl;; } return true; } void stunStopServer(StunServerInfo& info) { if (info.myFd > 0) closesocket(info.myFd); if (info.altPortFd > 0) closesocket(info.altPortFd); if (info.altIpFd > 0) closesocket(info.altIpFd); if (info.altIpPortFd > 0) closesocket(info.altIpPortFd); if (info.relay) { for (int i=0; ifd) { closesocket(relay->fd); relay->fd = 0; } } } } bool stunServerProcess(StunServerInfo& info, bool verbose) { char msg[STUN_MAX_MESSAGE_SIZE]; int msgLen = sizeof(msg); bool ok = false; bool recvAltIp =false; bool recvAltPort = false; fd_set fdSet; Socket maxFd=0; FD_ZERO(&fdSet); FD_SET(info.myFd,&fdSet); if ( info.myFd >= maxFd ) maxFd=info.myFd+1; FD_SET(info.altPortFd,&fdSet); if ( info.altPortFd >= maxFd ) maxFd=info.altPortFd+1; if ( info.altIpFd != INVALID_SOCKET ) { FD_SET(info.altIpFd,&fdSet); if (info.altIpFd>=maxFd) maxFd=info.altIpFd+1; } if ( info.altIpPortFd != INVALID_SOCKET ) { FD_SET(info.altIpPortFd,&fdSet); if (info.altIpPortFd>=maxFd) maxFd=info.altIpPortFd+1; } if (info.relay) { for (int i=0; ifd) { FD_SET(relay->fd, &fdSet); if (relay->fd >= maxFd) { maxFd=relay->fd+1; } } } } if ( info.altIpFd != INVALID_SOCKET ) { FD_SET(info.altIpFd,&fdSet); if (info.altIpFd>=maxFd) maxFd=info.altIpFd+1; } if ( info.altIpPortFd != INVALID_SOCKET ) { FD_SET(info.altIpPortFd,&fdSet); if (info.altIpPortFd>=maxFd) maxFd=info.altIpPortFd+1; } struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 1000; int e = select( maxFd, &fdSet, NULL,NULL, &tv ); if (e < 0) { int err = getErrno(); clog << "Error on select: " << strerror(err) << endl; } else if (e >= 0) { StunAddress4 from; // do the media relaying if (info.relay) { time_t now = time(0); for (int i=0; ifd) { if (FD_ISSET(relay->fd, &fdSet)) { char msg[MAX_RTP_MSG_SIZE]; int msgLen = sizeof(msg); StunAddress4 rtpFrom; ok = getMessage( relay->fd, msg, &msgLen, &rtpFrom.addr, &rtpFrom.port ,verbose); if (ok) { sendMessage(info.myFd, msg, msgLen, relay->destination.addr, relay->destination.port, verbose); relay->expireTime = now + MEDIA_RELAY_TIMEOUT; if ( verbose ) clog << "Relay packet on " << relay->fd << " from " << rtpFrom << " -> " << relay->destination << endl; } } else if (now > relay->expireTime) { closesocket(relay->fd); relay->fd = 0; } } } } if (FD_ISSET(info.myFd,&fdSet)) { if (verbose) clog << "received on A1:P1" << endl; recvAltIp = false; recvAltPort = false; ok = getMessage( info.myFd, msg, &msgLen, &from.addr, &from.port,verbose ); } else if (FD_ISSET(info.altPortFd, &fdSet)) { if (verbose) clog << "received on A1:P2" << endl; recvAltIp = false; recvAltPort = true; ok = getMessage( info.altPortFd, msg, &msgLen, &from.addr, &from.port,verbose ); } else if ( (info.altIpFd!=INVALID_SOCKET) && FD_ISSET(info.altIpFd,&fdSet)) { if (verbose) clog << "received on A2:P1" << endl; recvAltIp = true; recvAltPort = false; ok = getMessage( info.altIpFd, msg, &msgLen, &from.addr, &from.port ,verbose); } else if ( (info.altIpPortFd!=INVALID_SOCKET) && FD_ISSET(info.altIpPortFd, &fdSet)) { if (verbose) clog << "received on A2:P2" << endl; recvAltIp = true; recvAltPort = true; ok = getMessage( info.altIpPortFd, msg, &msgLen, &from.addr, &from.port,verbose ); } else { return true; } int relayPort = 0; if (info.relay) { for (int i=0; idestination.addr == from.addr && relay->destination.port == from.port) { relayPort = relay->relayPort; relay->expireTime = time(0) + MEDIA_RELAY_TIMEOUT; break; } } if (relayPort == 0) { for (int i=0; ifd == 0) { if ( verbose ) clog << "Open relay port " << relay->relayPort << endl; relay->fd = openPort(relay->relayPort, info.myAddr.addr, verbose); relay->destination.addr = from.addr; relay->destination.port = from.port; relay->expireTime = time(0) + MEDIA_RELAY_TIMEOUT; relayPort = relay->relayPort; break; } } } } if ( !ok ) { if ( verbose ) clog << "Get message did not return a valid message" < 0) && ( count < maxRet) ) { struct ifreq* ifr = (struct ifreq *)ptr; int si = sizeof(ifr->ifr_name) + sizeof(struct sockaddr); tl -= si; ptr += si; //char* name = ifr->ifr_ifrn.ifrn_name; //cerr << "name = " << name << endl; struct ifreq ifr2; ifr2 = *ifr; e = ioctl(s,SIOCGIFADDR,&ifr2); if ( e == -1 ) { break; } //cerr << "ioctl addr e = " << e << endl; struct sockaddr a = ifr2.ifr_addr; struct sockaddr_in* addr = (struct sockaddr_in*) &a; UInt32 ai = ntohl( addr->sin_addr.s_addr ); if (int((ai>>24)&0xFF) != 127) { addresses[count++] = ai; } #if 0 cerr << "Detected interface " << int((ai>>24)&0xFF) << "." << int((ai>>16)&0xFF) << "." << int((ai>> 8)&0xFF) << "." << int((ai )&0xFF) << endl; #endif } closesocket(s); return count; #endif } void stunBuildReqSimple( StunMessage* msg, const StunAtrString& username, bool changePort, bool changeIp, unsigned int id ) { assert( msg ); memset( msg , 0 , sizeof(*msg) ); msg->msgHdr.msgType = BindRequestMsg; for ( int i=0; i<16; i=i+4 ) { assert(i+3<16); int r = stunRand(); msg->msgHdr.id.octet[i+0]= r>>0; msg->msgHdr.id.octet[i+1]= r>>8; msg->msgHdr.id.octet[i+2]= r>>16; msg->msgHdr.id.octet[i+3]= r>>24; } if ( id != 0 ) { msg->msgHdr.id.octet[0] = id; } msg->hasChangeRequest = true; msg->changeRequest.value =(changeIp?ChangeIpFlag:0) | (changePort?ChangePortFlag:0); if ( username.sizeValue > 0 ) { msg->hasUsername = true; msg->username = username; } } static void stunSendTest( Socket myFd, StunAddress4& dest, const StunAtrString& username, const StunAtrString& password, int testNum, bool verbose ) { assert( dest.addr != 0 ); assert( dest.port != 0 ); bool changePort=false; bool changeIP=false; bool discard=false; switch (testNum) { case 1: case 10: case 11: break; case 2: //changePort=true; changeIP=true; break; case 3: changePort=true; break; case 4: changeIP=true; break; case 5: discard=true; break; default: cerr << "Test " << testNum <<" is unkown\n"; assert(0); } StunMessage req; memset(&req, 0, sizeof(StunMessage)); stunBuildReqSimple( &req, username, changePort , changeIP , testNum ); char buf[STUN_MAX_MESSAGE_SIZE]; int len = STUN_MAX_MESSAGE_SIZE; len = stunEncodeMessage( req, buf, len, password,verbose ); if ( verbose ) { clog << "About to send msg of len " << len << " to " << dest << endl; } sendMessage( myFd, buf, len, dest.addr, dest.port, verbose ); // add some delay so the packets don't get sent too quickly #ifdef WIN32 // !cj! TODO - should fix this up in windows clock_t now = clock(); assert( CLOCKS_PER_SEC == 1000 ); while ( clock() <= now+10 ) { }; #else usleep(10*1000); #endif } void stunGetUserNameAndPassword( const StunAddress4& dest, StunAtrString* username, StunAtrString* password) { // !cj! This is totally bogus - need to make TLS connection to dest and get a // username and password to use stunCreateUserName(dest, username); stunCreatePassword(*username, password); } void stunTest( StunAddress4& dest, int testNum, bool verbose, StunAddress4* sAddr ) { assert( dest.addr != 0 ); assert( dest.port != 0 ); int port = stunRandomPort(); UInt32 interfaceIp=0; if (sAddr) { interfaceIp = sAddr->addr; if ( sAddr->port != 0 ) { port = sAddr->port; } } Socket myFd = openPort(port,interfaceIp,verbose); StunAtrString username; StunAtrString password; username.sizeValue = 0; password.sizeValue = 0; #ifdef USE_TLS stunGetUserNameAndPassword( dest, username, password ); #endif stunSendTest( myFd, dest, username, password, testNum, verbose ); char msg[STUN_MAX_MESSAGE_SIZE]; int msgLen = STUN_MAX_MESSAGE_SIZE; StunAddress4 from; getMessage( myFd, msg, &msgLen, &from.addr, &from.port,verbose ); StunMessage resp; memset(&resp, 0, sizeof(StunMessage)); if ( verbose ) clog << "Got a response" << endl; bool ok = stunParseMessage( msg,msgLen, resp,verbose ); if ( verbose ) { clog << "\t ok=" << ok << endl; clog << "\t id=" << resp.msgHdr.id << endl; clog << "\t mappedAddr=" << resp.mappedAddress.ipv4 << endl; clog << "\t changedAddr=" << resp.changedAddress.ipv4 << endl; clog << endl; } if (sAddr) { sAddr->port = resp.mappedAddress.ipv4.port; sAddr->addr = resp.mappedAddress.ipv4.addr; } } NatType stunNatType( StunAddress4& dest, bool verbose, bool* preservePort, // if set, is return for if NAT preservers ports or not bool* hairpin, // if set, is the return for if NAT will hairpin packets int port, // port to use for the test, 0 to choose random port StunAddress4* sAddr // NIC to use ) { assert( dest.addr != 0 ); assert( dest.port != 0 ); if ( hairpin ) { *hairpin = false; } if ( port == 0 ) { port = stunRandomPort(); } UInt32 interfaceIp=0; if (sAddr) { interfaceIp = sAddr->addr; } Socket myFd1 = openPort(port,interfaceIp,verbose); Socket myFd2 = openPort(port+1,interfaceIp,verbose); if ( ( myFd1 == INVALID_SOCKET) || ( myFd2 == INVALID_SOCKET) ) { cerr << "Some problem opening port/interface to send on" << endl; return StunTypeFailure; } assert( myFd1 != INVALID_SOCKET ); assert( myFd2 != INVALID_SOCKET ); bool respTestI=false; bool isNat=true; StunAddress4 testIchangedAddr; StunAddress4 testImappedAddr; bool respTestI2=false; bool mappedIpSame = true; StunAddress4 testI2mappedAddr; StunAddress4 testI2dest=dest; bool respTestII=false; bool respTestIII=false; bool respTestHairpin=false; bool respTestPreservePort=false; memset(&testImappedAddr,0,sizeof(testImappedAddr)); StunAtrString username; StunAtrString password; username.sizeValue = 0; password.sizeValue = 0; #ifdef USE_TLS stunGetUserNameAndPassword( dest, username, password ); #endif int count=0; while ( count < 7 ) { struct timeval tv; fd_set fdSet; #ifdef WIN32 unsigned int fdSetSize; #else int fdSetSize; #endif FD_ZERO(&fdSet); fdSetSize=0; FD_SET(myFd1,&fdSet); fdSetSize = (myFd1+1>fdSetSize) ? myFd1+1 : fdSetSize; FD_SET(myFd2,&fdSet); fdSetSize = (myFd2+1>fdSetSize) ? myFd2+1 : fdSetSize; tv.tv_sec=0; tv.tv_usec=150*1000; // 150 ms if ( count == 0 ) tv.tv_usec=0; int err = select(fdSetSize, &fdSet, NULL, NULL, &tv); int e = getErrno(); if ( err == SOCKET_ERROR ) { // error occured cerr << "Error " << e << " " << strerror(e) << " in select" << endl; return StunTypeFailure; } else if ( err == 0 ) { // timeout occured count++; if ( !respTestI ) { stunSendTest( myFd1, dest, username, password, 1 ,verbose ); } if ( (!respTestI2) && respTestI ) { // check the address to send to if valid if ( ( testI2dest.addr != 0 ) && ( testI2dest.port != 0 ) ) { stunSendTest( myFd1, testI2dest, username, password, 10 ,verbose); } } if ( !respTestII ) { stunSendTest( myFd2, dest, username, password, 2 ,verbose ); } if ( !respTestIII ) { stunSendTest( myFd2, dest, username, password, 3 ,verbose ); } if ( respTestI && (!respTestHairpin) ) { if ( ( testImappedAddr.addr != 0 ) && ( testImappedAddr.port != 0 ) ) { stunSendTest( myFd1, testImappedAddr, username, password, 11 ,verbose ); } } } else { //if (verbose) clog << "-----------------------------------------" << endl; assert( err>0 ); // data is avialbe on some fd for ( int i=0; i<2; i++) { Socket myFd; if ( i==0 ) { myFd=myFd1; } else { myFd=myFd2; } if ( myFd!=INVALID_SOCKET ) { if ( FD_ISSET(myFd,&fdSet) ) { char msg[STUN_MAX_MESSAGE_SIZE]; int msgLen = sizeof(msg); StunAddress4 from; getMessage( myFd, msg, &msgLen, &from.addr, &from.port,verbose ); StunMessage resp; memset(&resp, 0, sizeof(StunMessage)); stunParseMessage( msg,msgLen, resp,verbose ); if ( verbose ) { clog << "Received message of type " << resp.msgHdr.msgType << " id=" << (int)(resp.msgHdr.id.octet[0]) << endl; } switch( resp.msgHdr.id.octet[0] ) { case 1: { if ( !respTestI ) { testIchangedAddr.addr = resp.changedAddress.ipv4.addr; testIchangedAddr.port = resp.changedAddress.ipv4.port; testImappedAddr.addr = resp.mappedAddress.ipv4.addr; testImappedAddr.port = resp.mappedAddress.ipv4.port; respTestPreservePort = ( testImappedAddr.port == port ); if ( preservePort ) { *preservePort = respTestPreservePort; } testI2dest.addr = resp.changedAddress.ipv4.addr; if (sAddr) { sAddr->port = testImappedAddr.port; sAddr->addr = testImappedAddr.addr; } count = 0; } respTestI=true; } break; case 2: { respTestII=true; } break; case 3: { respTestIII=true; } break; case 10: { if ( !respTestI2 ) { testI2mappedAddr.addr = resp.mappedAddress.ipv4.addr; testI2mappedAddr.port = resp.mappedAddress.ipv4.port; mappedIpSame = false; if ( (testI2mappedAddr.addr == testImappedAddr.addr ) && (testI2mappedAddr.port == testImappedAddr.port )) { mappedIpSame = true; } } respTestI2=true; } break; case 11: { if ( hairpin ) { *hairpin = true; } respTestHairpin = true; } break; } } } } } } // see if we can bind to this address //cerr << "try binding to " << testImappedAddr << endl; Socket s = openPort( 0/*use ephemeral*/, testImappedAddr.addr, false ); if ( s != INVALID_SOCKET ) { closesocket(s); isNat = false; //cerr << "binding worked" << endl; } else { isNat = true; //cerr << "binding failed" << endl; } if (verbose) { clog << "test I = " << respTestI << endl; clog << "test II = " << respTestII << endl; clog << "test III = " << respTestIII << endl; clog << "test I(2) = " << respTestI2 << endl; clog << "is nat = " << isNat <. * */ // Local Variables: // mode:c++ // c-file-style:"ellemtel" // c-file-offsets:((case-label . +)) // indent-tabs-mode:nil // End: stund/wnattest.bat0000644000175000017500000000206411710231326012346 0ustar kkkk@echo off rem wnattest.bat if defined %4 ( goto usage ) else if defined %3 ( goto start ) else ( goto usage ) :start stunner %1 -i %2 -i2 %3 if %errorlevel% == -1 ( echo "ERROR! the STUN test program had an error" ( ) else if %errorlevel% == 10 ( echo "[PASS] (Address) Restricted Cone NAT with Hairpinning" ) else if %errorlevel% == 21 ( echo "[PASS] Port Restricted Cone NAT with Hairpinning" ) else if %errorlevel% == 8 ( echo "[No NAT] You have open internet access" ) else if %errorlevel% == 2 ( echo "[FAIL] Your (Address) Restricted Cone NAT doesn't do hairpinning" ) else if %errorlevel% == 3 ( echo "[FAIL] Your Port Restricted Cone NAT doesn't do hairpinning" ) else ( echo "[FAIL] You have a NAT or Firewall type which is NOT RECOMMENDED. " if %errorlevel% LSS 8 ( echo "It also does not support hairpinning" ) else ( each "it does at least support hairpinning" ) ) goto end :usage echo Usage: echo wnattest echo. echo Example: wnattest 1.1.1.2 192.168.0.2 192.168.0.3 echo. :end stund/tlsServer.cxx0000644000175000017500000003206611710231326012527 0ustar kkkk /* This program takes no arguments. It opens the STUN tcp port and rus a tls server on it. */ #include #include #include #include #include #include #include #include #include #include #include #ifdef WIN32 #include #include #include #endif #ifndef WIN32 #include #include #include #include #include #include #include #endif #ifdef WIN32 # include # include # include # include # include typedef unsigned int u_int32_t; #endif #include #include #include #include #include #ifdef __MACH__ typedef int socklen_t; #endif #include "stun.h" using namespace std; #define MAX_CONNECTIONS 64 #ifdef WIN32 typedef int socklen_t; //#define errno WSAGetLastError() typedef SOCKET Socket; #else typedef int Socket; static const Socket INVALID_SOCKET = -1; static const int SOCKET_ERROR = -1; #endif // TODO - !cj! - need to deal with closing connections void makeSocketNonBlocking(Socket fd) { #if WIN32 unsigned long noBlock = 1; int errNoBlock = ioctlsocket( fd, FIONBIO , &noBlock ); if ( errNoBlock != 0 ) { assert(0); } #else int flags = fcntl( fd, F_GETFL, 0); int errNoBlock = fcntl(fd, F_SETFL, flags | O_NONBLOCK ); if ( errNoBlock != 0 ) // !cj! I may have messed up this line { assert(0); } #endif } int main() { #ifdef WIN32 WORD wVersionRequested = MAKEWORD( 2, 2 ); WSADATA wsaData; int err; err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { // could not find a usable WinSock DLL //cerr << "Could not load winsock" << endl; assert(0); // is this is failing, try a different version that 2.2, 1.0 or later will likely work exit(1); } #endif // contexts for each connection SSL* ssl[MAX_CONNECTIONS]; // buffers for each connection BIO* bio[MAX_CONNECTIONS]; // file descriptors for each connection Socket fd[MAX_CONNECTIONS]; // ip address of other side of connection int peerip[MAX_CONNECTIONS]; // root cert list X509_STORE* certAuthorities; // my public cert X509* publicCert; // my private key EVP_PKEY* privateKey; // SSL Context SSL_CTX* ctx; Socket mFd; char* password = "password"; for ( int i=0; i 0 ) { FD_SET(fd[i], &read); size = ( int(fd[i]+1) > size) ? int(fd[i]+1) : size; } } // do a select unsigned long ms = 500; struct timeval tv; tv.tv_sec = (ms/1000); tv.tv_usec = (ms%1000)*1000; int e = select(size, &read, NULL, NULL, &tv); cerr << "." ; // process any new connections if ( FD_ISSET(mFd, &read)) { cerr << "Got a new connection" << endl; // find an unused connection int i=0; for ( ; i= MAX_CONNECTIONS ) { cerr << "Ran out of connections to use "<. * */ // Local Variables: // mode:c++ // c-file-style:"ellemtel" // c-file-offsets:((case-label . +)) // indent-tabs-mode:nil // End: stund/nattest0000644000175000017500000000333111710231326011410 0ustar kkkk#!/bin/bash # nattest shell script # set defaults # Interfaces typically begin eth on Linux, en on Macintosh, le or hme on Solaris # type ifconfig -a or ifconfig -l to see a list of all interfaces serverint=eth0 clientint=eth1 serverip1=1.1.1.2 serverip2=1.1.1.3 servermask=255.255.255.0 clientip1=192.168.0.2 clientip2=192.168.0.3 clientmask=255.255.255.0 # print warning, get confirmation cat nattestwarning.txt read -p "Are you sure you want to run this? [yes]" confirm case $confirm in [nN] ) exit;; [nN][oO] ) exit;; esac # off we go then.... # add second IP address to each interface ifconfig $serverint $serverip2 netmask 255.255.255.255 alias ifconfig $clientint $clientip2 netmask 255.255.255.255 alias # for Solaris, use these instead # ifconfig ${serverint}:1 $serverip2 netmask $servermask # ifconfig ${clientint}:1 $clientip2 netmask $clientmask ./stund -h $serverip1 -a $serverip2 -b # verify server is running ./stunner $serverip1 -i $clientip1 -i2 $clientip2 # process results of stunner and print pass/fail case "$?" in 10 ) echo "[PASS] (Address) Restricted Cone NAT with Hairpinning";; 11 ) echo "[PASS] Port Restricted Cone NAT with Hairpinning";; 8 ) echo "[No NAT] You have open internet access";; 2 ) echo "[FAIL] Your (Address) Restricted Cone NAT doesn't do hairpinning";; 3 ) echo "[FAIL] Your Port Restricted Cone NAT doesn't do hairpinning";; -1 ) echo "ERROR! the STUN test program had an error";; * ) echo "[FAIL] You have a NAT or Firewall type which is NOT RECOMMENDED.";; esac # cleanup killall -HUP stund ifconfig $serverint $serverip2 -alias ifconfig $clientint $clientip2 -alias # for Solaris, use these instead # ifconfig ${serverint}:1 unplumb # ifconfig ${clientint}:1 unplumb stund/WinStun/0000755000175000017500000000000012445636075011432 5ustar kkkkstund/WinStun/WinStunDlg.h0000644000175000017500000000125311710231326013622 0ustar kkkk// WinStunDlg.h : header file // #pragma once // CWinStunDlg dialog class CWinStunDlg : public CDialog { // Construction public: CWinStunDlg(CWnd* pParent = NULL); // standard constructor // Dialog Data enum { IDD = IDD_WINSTUN_DIALOG }; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support // Implementation protected: HICON m_hIcon; // Generated message map functions virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() public: afx_msg void OnBnClickedTest(); // the name of the stun server to use CString mServerName; }; stund/WinStun/WinStunDlg.cpp0000644000175000017500000001216211710231326014156 0ustar kkkk #include "stdafx.h" #include "WinStun.h" #include "WinStunDlg.h" #include #include "../stun.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // CAboutDlg dialog used for App About class CAboutDlg : public CDialog { public: CAboutDlg(); // Dialog Data enum { IDD = IDD_ABOUTBOX }; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support // Implementation protected: DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) END_MESSAGE_MAP() // CWinStunDlg dialog CWinStunDlg::CWinStunDlg(CWnd* pParent /*=NULL*/) : CDialog(CWinStunDlg::IDD, pParent) , mServerName(_T("")) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CWinStunDlg::DoDataExchange(CDataExchange* pDX) { mServerName = _T("larry.gloo.net"); CDialog::DoDataExchange(pDX); DDX_Text(pDX, IDC_SERVER, mServerName); DDV_MaxChars(pDX, mServerName, 128); } BEGIN_MESSAGE_MAP(CWinStunDlg, CDialog) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() //}}AFX_MSG_MAP ON_BN_CLICKED(IDC_TEST, OnBnClickedTest) END_MESSAGE_MAP() // CWinStunDlg message handlers BOOL CWinStunDlg::OnInitDialog() { CDialog::OnInitDialog(); // Add "About..." menu item to system menu. // IDM_ABOUTBOX must be in the system command range. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here return TRUE; // return TRUE unless you set the focus to a control } void CWinStunDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialog::OnSysCommand(nID, lParam); } } // If you add a minimize button to your dialog, you will need the code below // to draw the icon. For MFC applications using the document/view model, // this is automatically done for you by the framework. void CWinStunDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0); // Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } } // The system calls this function to obtain the cursor to display while the user drags // the minimized window. HCURSOR CWinStunDlg::OnQueryDragIcon() { return static_cast(m_hIcon); } void CWinStunDlg::OnBnClickedTest() { // TODO: Add your control notification handler code here CString& server = mServerName; CEdit* display = (CEdit*)GetDlgItem(IDC_RESULT); assert(display); display->SetWindowText( CString( _T("Running...\r\n")) ); CEdit* edit = (CEdit*)GetDlgItem(IDC_SERVER); assert(edit); edit->GetWindowText(server); StunAddress4 stunServerAddr; LPCTSTR str; str = server; char* s; s = (char*)str; stunParseServerName( s, stunServerAddr); bool verbose = false; StunAddress4 sAddr; sAddr.port = 0; sAddr.addr = 0; bool preservePort; bool hairpin; int port=0; NatType stype = stunNatType( stunServerAddr, verbose, &preservePort, &hairpin, port, &sAddr ); CString text; switch (stype) { case StunTypeOpen: text = _T("No NAT detected - VoIP should work"); break; case StunTypeConeNat: text = _T("Cone Nat detect - VoIP will work with STUN"); break; case StunTypeRestrictedNat: text = _T("Address restricted NAT detected - VoIP will work with STUN"); break; case StunTypePortRestrictedNat: text = _T("Port restricted NAT detected - VoIP will work with STUN"); break; case StunTypeSymNat: text = _T("Symetric - VOIP will NOT work"); break; case StunTypeSymFirewall: text = _T("Symetric firewall - VOIP will NOT work"); break; case StunTypeBlocked: text = _T("Could not reach the stun server - check server name is correct"); break; default: text = _T("Unkown NAT type"); break; } text += _T("\r\n"); if (preservePort) { text+= _T("Preserves port number\r\n"); } else { text+= _T("Does not preserve port number\r\n"); } if (hairpin) { text+= _T("Supports hairpin of media\r\n"); } else { text+= _T("Does not supports hairpin of media\r\n"); } CString strAddr; strAddr.Format(_T("Public IP address: %d.%d.%d.%d"), (sAddr.addr>>24)&0xFF,(sAddr.addr>>16)&0xFF,(sAddr.addr>>8)&0xFF,(sAddr.addr>>0)&0xFF ); text += strAddr; display->SetWindowText( text + CString( _T("\r\n")) ); } stund/WinStun/WinStun.vcproj0000644000175000017500000001021211710231326014242 0ustar kkkk stund/WinStun/res/0000755000175000017500000000000012445636075012223 5ustar kkkkstund/WinStun/res/WinStun.manifest0000644000175000017500000000124311710231326015342 0ustar kkkk Your app description here stund/WinStun/res/WinStun.ico0000644000175000017500000005217611710231326014321 0ustar kkkk 00h– èþ(æ 00¨ ¨¶h^"00¨Æ' ¨ nDhQ(0`€€€€€€€€€€€€ÀÀÀÿÿÿÿÿÿÿÿÿÿ×wwwwwwwwwwwwwwwwwwwwwwÝ׈ˆˆˆˆˆˆˆˆˆ‡øˆˆˆˆˆˆˆˆˆ‡Ý×ÿ‡ÿ‡Ý×øøøøøøøø‡øøøøø‡Ý×ÿ‡ÿ‡Ý×øøøøøøøø‡øøøøøñø‡Ý×ÿ‡ÿ‡Ý×øøøøøøøø‡øøøøøøøø‡Ý×ÿ‡ÿ‡Ý×øøøøøøøø‡øøøøøøøø‡Ý×ÿ‡ÿ‡Ý×øøøøøø‡øøøøøøøø‡Ý×ÿ‡ÿ‡Ý×øøøøøøøø‡øøøøøøøø‡Ý×ÿ‡ÿ‡Ý×øøøøøøøø‡øøøøøøøø‡Ý×ÿ‡ÿ‡Ý×øøøøøøøø‡øøøøøñø‡Ý×ÿ‡ÿ‡Ý×øøøøø‡øøøøø‡Ý×ÿ‡ÿ‡Ý×ÿÿÿÿÿÿÿÿÿÿ‡ÿÿÿÿÿÿÿÿÿÿ÷Ý×wwwwwwwwwwwwwwwwwwwwwwÝÝxˆˆˆˆxˆˆˆˆˆˆˆˆˆˆxˆˆˆˆ}ÝÝ׈ˆˆˆøøøøøøøøøøxˆˆˆ‡ÝÝÝÝxˆˆˆˆxˆˆˆ}ÝÝÝÝ×wwwøñøøøñøøwwwwÝÝÝÝÝÝÝÝ݈}ÝÝÝÝÝÝÝÝÝÝÝÝøñøñøø}ÝÝÝÝÝÝÝÝÝÝÝ݈}ÝÝÝÝÝÝÝÝÝÝÝÝøñøñøø}ÝÝÝÝÝÝÝÝÝÝÝ݈}ÝÝÝÝÝÝÝÝÝÝÝÝøñøø}ÝÝÝÝÝÝÝÝÝÝÝ݈}ÝÝÝÝÝÝÝÝÝÝÝÝøñøñøø}ÝÝÝÝÝÝÝÝÝÝÝ݈}ÝÝÝÝÝÝÝÝÝÝÝÝøñøñøø}ÝÝÝÝÝÝÝÝÝÝÝ݈}ÝÝÝÝÝÝÝÝÝÝÝÝøñøñøø}ÝÝÝÝÝÝÝÝÝÝÝ݈}ÝÝÝÝÝÝÝÝÝÝÝÝøñøøøñøø}ÝÝÝÝÝÝÝÝÝÝÝ݈}ÝÝÝÝÝÝÝÝÝÝÝÝøøøøøøøøøø}ÝÝÝÝÝÝÝÝÝÝÝÝÿÿÿÿÿÿÿÿÿÿ}ÝÝÝÝÝÝÝÝÝÝÝÝwwwwwwwwwww}ÝÝÝÝÝÝÝÝÝÝÝÝ׈ˆˆˆˆˆˆˆˆ‡ÝÝÝÝÝÝÝÝÝÝÝÝÝÝxˆˆˆˆˆˆˆˆ}ÝÝÝÝÝÝÝÝÝÝÝÝÝÝ×wwwwwwwwÝÝÝÝÝÝÝÝ€€€€€€€€€€€€€€€€€€€€€€€Ààðø?ÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿø?ÿÿüÿÿþÿÿ( @€€€€€€€€€€€€ÀÀÀÿÿÿÿÿÿÿÿÿÿ×wwwwwwwwwwwwwwÝ׈ˆˆˆˆˆ‡øˆˆˆˆˆ‡Ý×ÿ‡ÿ‡Ý×øøøøø‡øøø‡Ý×ÿ‡ÿ‡Ý×øøøøø‡øñøøø‡Ý×ÿ‡ÿ‡Ý×øøø‡øñøøø‡Ý×ÿ‡ÿ‡Ý×øøøøø‡øñøøø‡Ý×ÿ‡ÿ‡Ý×øøø‡øøø‡Ý×ÿ‡ÿ‡Ý×ÿÿÿÿÿÿ‡ÿÿÿÿÿÿ÷Ý×wwwwwwwwwwwwwwÝÝxˆˆˆˆˆˆˆˆxˆˆ}ÝÝ׈ˆøøøøøøxˆ‡ÝÝÝÝxˆˆxˆ}ÝÝÝÝ×wøññøwwÝÝÝÝÝÝ݈}ÝÝÝÝÝÝÝÝøø}ÝÝÝÝÝÝÝ݈}ÝÝÝÝÝÝÝÝøø}ÝÝÝÝÝÝÝ݈}ÝÝÝÝÝÝÝÝøøñø}ÝÝÝÝÝÝÝ݈}ÝÝÝÝÝÝÝÝøøøøøø}ÝÝÝÝÝÝÝÝÿÿÿÿÿÿ}ÝÝÝÝÝÝÝÝwwwwwww}ÝÝÝÝÝÝÝÝ׈ˆˆˆˆ‡ÝÝÝÝÝÝÝÝÝÝxˆˆˆˆ}ÝÝÝÝÝÝÝÝÝÝ×wwwwÝÝÝÝÝÝ€€€€€€€€€€€€€€€Ààðø?ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿÿÀÿÿàÿ( €€€€€€€€€€€€ÀÀÀÿÿÿÿÿÿÿÿÿÿwwwwwww}xˆˆ‡ˆˆˆ}xˆ‡ˆˆ}xˆ‡ˆ}x‡ˆˆ}xˆ‡ˆ}x‡ˆˆ}xˆˆ‡ˆˆˆ}wwwwwww}ׇˆˆˆ‡‡ÝÝwˆ‡}ÝÝ׈‡ÝÝÝׇÝÝÝׇÝÝÝ׈ˆˆ‡ÝÝÝ×wwwwÝ݇‡Ýøø‡ø‡Ý€‡Àà‡Ýàøàø‡àà‡Ý(0`ŽwXkqN]tno‰0-Š1-Œ6-Ë­ª´‰‚©ym¶Ž…À•ÏËÊ”C,“B,¯„w‚:"£o\œhP”]>Át©e=¼‡g»†gÀrÀŽlÀg¾ƒNÉ“bÑ›i²t5³u6Ë‘XÄŒVÛ°†ê̯À5ËŽIÙ¦nÚ§oä»åÀ™óÜÃÃ6dž:Ê‹=È‹Añغˌ=Ý­lÜ­pÞ±w彉ðÕ²üóçÊŒ7ΗFã¸{ïÒ¨øêÕúîÜÁ~ÈŠ'Û©]îÏ õÞ¸õà¾Ú¤JóÖ¡óبôÚ­óÛ°ôÝ´õâÂöæËÙ¡/ïÍŠïÏŽðÑ”ðÒ–ðÓšòÕŸò×¥ìÄmíÈzî˃é¼NëÀ]è¹:I™H–\¦OU—JI¡=c®Y\™UL†Gaœ]gŸcqªmj¶er¹ny»v‚¿n kQ‰OW‹V…Áƒ|¯zŠÂ‰Â…²„ÄŽ’Ç”“È•˜Êš›Ë–É™›ÌžœÌŸ¡Î¤¬Õ°»Ü¾¿Þ¤Щ°Ö´¶ÚºÇâÊËäÎÁßÅÝíßÔèØÑåÕL]áëäd¾‰n“çöî@‡b~ϧÑïà·æÐÄêØÚòçŒÖ¶ôûø˜ÝÃ>88+/ø÷÷÷÷÷h\^„ˆ‰}qq€’‘•”“—£[`//"QRT$1=>>8+2ø÷÷÷÷÷j\^‚„ˆ‰sccy‹’‘•”“£\`2/"OQ$%=>>*2ø÷÷÷÷÷i\^‚„ˆsccy‹Œ‘•”£\a//"NO66**L=>(2ø÷÷÷÷÷i\]~ƒ„rccyŽ‹Œ‘•£\a//"WNFTHI*++LL=(/ø÷÷÷÷÷h\^|~ƒrccsŠŽ‹Œ‘¡\`//'VWRFTHJCDKLL)2ø÷÷÷÷÷j\]x|~rccp~‹’¡\_//'VVQRFTHJCDKL(/ø÷÷÷÷÷i\^wx|~pcccccbŽ‹Œ¡\`//'UVOQRFGHJCDK(/ø÷÷÷÷÷i\]wwx|pcckrssŠŽ¡\a//0UUNOQRSGHIJD(2ø÷÷÷÷÷i\^vwwxpccr†…‰ŠŽ¡\`///YUWNOQRFTHIJ)/ø÷÷÷÷÷j\]uvwwmccp‚†‡‰ŠŽ¡\`//9YYVWNO5;*THI)2ø÷÷÷÷÷j\]uuvwmccp‚†…‰Šœ\a//9XYVVWNSTH)2ø÷÷÷÷÷i\]ouuvmccbbbbbs‰œ\a//@XX0RST)/ø÷÷÷÷÷i\]oouulefffggkt‡‰œ\`/2@ZXX:;NPRF(/ø÷÷÷÷÷h\]loouuvwwx|~‚†…œ\_2/@ZZXXYYUUUVWNOPQ(/ø÷÷÷÷÷i\]ffggkkqqqzzz{{{–\_//?MMMMEEEAAAA33452ø÷÷÷÷÷i\\\\\\\\\\\\\\\\\\\`//&&&&&--&&&&-&&&&./÷÷÷÷÷÷illlllllll›¤¤¤¤¤¤¤¤¤¤È##" ÷÷÷÷÷÷÷÷ï¢¢š ŸžžÁ®­®®®®¯®®­®­®­®®­­®­   ÷÷÷÷÷÷÷÷÷÷ï¢šš ŸžÀ®¾¥¥¦¦¦¥¥¥¥¥¥¦¥¥¦¦°­  ÷÷÷÷÷÷÷÷÷÷÷÷ïššš ŸÀ­êËÌÌÍÍÎÏп¿ÑÑ»¼¼º©­  ÷÷÷÷÷÷÷÷÷÷÷÷÷÷ïšš  À®êÊËÌÜÝÞÎÏпËÌÌÇÒ¿§­ ÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷ïïïïïÀ®êàÊËõôÍÎÏÐõõÑÇ¿§® ÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷Ä­éàÊÊõõÝõóÏõõÑ»¬§®ñø÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷À®éÞßàõõÜõÎõõ¿Ñ¬©­òø÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷Ä®éÛÞàõõÜõâõõ¿¿¬§­ñø÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷Ä®éÜÉÞõöõöõöõп´§®ñø÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷Ä®éÙÜÉõôÐд§®ñø÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷Ä­îØÙÜõÓÓôÎϳª®òø÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷À®îÖØÙõÖØõÎγ©®ñø÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷À¯îÕרôöõ×ÖõöõÍι«®ñø÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷À¯îÓÕÖõõÉßàÊõõÆÍ¹§®òø÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷À­íÓÓÕõõÛÉßàõõÌÆ¹§®òø÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷Ä®íÓÓÓóõóÙÜÉßóõóË̸«®òø÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷À®íäÓÓÓÕרÙÛÝßàÊËË·«®ñø÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷À­ðééêêêääåååææçèèÕ°¯ñø÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷À­ÂÃÂÂÃÂÃÃÃÃÃÂÂÂÃî¯òø÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷Å­­®¯­­®­®­­­¯­®­­­®½ì÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷ëᨼ¼»º¿¬´³²¸¶¶±±µÅì÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷켨¼¼»º¿¬´³²¸¶¶µÔì÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷ì¼¼¼Ç»º¿¬´³²¸¸âì÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷ìãâââââÚÚÚÚÔìì÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷ÿÿÿÿÿÿðàÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀà?ðøÿüÿþÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿð?ÿÿøÿÿüÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿ( @ŽnPh„ixðçèѶ¶Ò··¼•”Š1-Ŧ ­€vÁŸ—°…yÀ•Š¥uf¨bJÆŽÅœ—O1§aAœgO§`>©eD´„l™„¨d=¤iIÂŽpÈ¢ŽÖ·¦©d8£hEÁs³rHÂgè͹ˆXÁ†OດéȧÀ5çÄïØÀÄ„:Ê‹=ݰzçÁ”îÔ¶ËŒ=ÒšSÜ­n澋óÝ¿Î;Ò˜HÛ©^ä»êÈ—öäË÷èÓùìÚûòåÑ–;áµqðÓ¦òÙ²òÛ¸ôáÂÝ©L߯_óبñÖ©óÚ­ôÛ°õß¹Ù¢5îÍŠðÑ•ðÓšðÔŸìÃjîÌ…Ø é¼Lè¹3_s-G‘CˆB‡H–BvBuAuBvD‹7m3eH%0_J.M5>w+I4D2P‘=F‚9I¡=J¡=T©Gf¯[M„Ea³Yg±^o³g`œZfµ_r¸ld`y·t¹zuºqq¢n„¼„²‚€¿~…Áƒˆ¾†”ƔŎ˜È™ÊžœÌž–Ê™›Ìž›Ëž¢Î¥¦Ò©‚”ƒƒ•„´Ù··Úº»Ü¾ÇâÊ×êÙÛìݬԱÌäϺ׿éóë|ÁŽ‘Ê£‡ŠšÐ­ Ø·¬ÞùäÏ×ñäãõíÄêÚ†… ¨§Z›Ÿ7s‰8tŠ5u“X°û^µüd·ü3Zz²ÜÿÄäÿ#”÷$•ø$•÷8žù?¡úI¥úS«ú\²üb˜ÇŒÇý¦Ôþ¼àÿ*ì>–íZ¬ú~¿ý‘Æû›Íý×ëÿãñÿûýÿ#Šöêôÿ¹Óò¹ÒñÚëÿ#€õ$€õWpWoÊàþÐäþ/€õ3‚õ8†ö<‰öX—îe“رù”¾úœÃú Æû¦Éû®Îû·Ôý¸Õý¿Ùþ²Èè`™ödœöl¡÷s¦øt¨øy«øTr£‡´ùˆµùyØy׺úhözØ¡¸à@sÛGxÛv•Ñ6gÓDrÔKvÕNxÔUܤÕÌÕé8^Äj}¼!9´,£'“»»¾üüýýýýýýýýýýýýýüýýýýýýýýýýýýýüüüü ŠŠ‹ŠŠ‹‹Š‹ŠŠŠýýýüüü]ZZZZZZZZZZZWV-1---------1-ýüüü\g–™šš››œœŸŸmV2.AHBC5D;<<(-ýüüü^i†‰ƒz|“‘•kV2.P:#!!+=>(-ýüüü\e…„coŽ“‘kV239 $=(-ýüüü]e…{coŽ“kV73@ GJ'0<(-ýüüü^e~xco’ŒŽ“kV78@ OGJKD;*1ýüüü]d}~wca``€ŽkV78F OOGJKD*1ýüüü\dy}rch{ˆŒŽkV7EF MNOGIK/1ýüüü\buyrcj€‡‰’ŒkV?EE RR.#:I/-ýüüü[btuncfssv‚’kV?LE&%"9G41ýüüü]_ptqhhhjjˆkV?LTE@NO41ýüüü]_mptuy}~€„lV6SUTTQQQRRN91ýüüü[WXXXYXXYXYYWV-)))))))))),,ýüüü˜ž”’™—¢¥£££¤£©ÉÉÈÉÉâ$üüüüüûžžŸ´Á²²¦¦³§§¨¨¨§­ üüüüüüüûž´ÇÓÔÖרÚÊËÅ¿«¬ üüüüüüüüüûû¡æÆçÓõøòçãø÷Å«­ üüüüüüüüüüüüüæÆãçõîèøË·¬öýüüüüüüüüüüüüüüüüåÇÒãñîÜùøÊª¬íýüüüüüüüüüüüüüüüüæÇáÒðøÚª¬æýüüüüüüüüüüüüüüüüæÆßáïÜøøÙ¶®æýüüüüüüüüüüüüüüüüæÆÞßïùß÷úø×¶¬æýüüüüüüüüüüüüüüüüéÇÝÞïðãçøøÖ½­æýüüüüüüüüüüüüüüüüåÆÜÝëøìÒäøøÕ½­éýüüüüüüüüüüüüüüüüéÇÐÜÝÞàáÒÞßÔ¼­æýüüüüüüüüüüüüüüüüæÁÌÌÍÍÍÎÎÏÏÏÏ®æýüüüüüüüüüüüüüüüü󹺺²²±±±°°¯¯¸óüüüüüüüüüüüüüüüüüüêÀ¿¿Å«·¶½µ»ÐêüüüüüüüüüüüüüüüüüüüüôÀ¿¾«·¶µÑêüüüüüüüüüüüüüüüüüüüüüüôÄÃÄÃÃÃÛêüüüüüüüüüüüüüÀ€€€€€€€€€€€€€€€Ààð?þÿþÿþÿþÿþÿþÿþÿþÿþÿþÿÿÿÿ€ÿÿÀÿ( uVh‘tz·Ž…Ô·¯Â™„ T,©d<Ú¼«Ê”rÊ”s©d6¨c6»YŠ`Ï›oˆUÖ¡qðÚÆÕ¡pÖ¢qݱ…øëÞÒ˜XÒ™YÔŸeÓžeÌIÓœYÒ™XÓšQÓ›QôâËȈ)ÈŒ7ëÈ”óݾЖ8Ñ—<Ò˜?èÇòÙ²ðÒŸõà»ñצ_s-CŠ<<==.ECK2LPV.$ E@J3MOU.  !D?H31IT.-,%B;G1JKS.( ) *E9A011R.&#++E/4678:."&' NQWhX^XXXe Šrpqƒt}~]mvŽŒ†\ˆl{‹…[‰iz„Z‰jy‡w‚€Y‰djklnoc‰sgba`_f|ux||||d}ca€ŽV7 GJ*1€üüÀdyðchðˆŒðV7ð ðOGð/1øüü(0` # # # # # # # #! # #! #! # # # # # # # #gdc # # #! # # # # # # # # # # # # # # # # #BuAuBvBvBvBvAuAuBvBvAuBuBvBvBvBvAuAuBv! #­o3²t5²t5²t5²t5²t5²t5²t5²t5²t6²t5²t5³u6²t5²t5²t5²t6²t5²t5²t5! #! #a„ZI—I–I–I—H–I—I–H–I–I–I–I–I–H–H–H–I–I—I–BvÊ‹=Ê‹=ËŒ=Ê‹=Ê‹=Ê‹=Ë‹=Ë‹=Ê‹=Ê‹=Ê‹=Ê‹=Ë‹=Ê‹=Ê‹=ËŒ=Ê‹=Ê‹=ËŒ=Ê‹=—lR! #a„YI—é»Hé½RΗF©d7©d8©d9©d<¨d=©e@ã¹vïÎðÑ”ðÒ™òÕ Ú§oË‹=—lR! #a„YH–è»Hé½Rê¿ZëÁ`ëÃiìÄníÇvíÇyîÊîˆïÎðÑ”ðÒ™Ú¦nÊ‹=˜lS! #b…ZH–=zBƒ2D„4E„9F…:H†?H†@K‡DLˆHNˆJQ‰OR‰OUŠSV‹UW‹WYŒZMŽ^I–BuÊ‹=ËŒ=Á~ØŸ!Ø *Ù¢6Ù¢;Ù£CÚ¥KÚ¦PÚ§WÛ¨ZÛª`ÛªcÛ¬jÝ­nÝ®qݰwÒ™`ËŒ=˜lR! #b„ZI–I—I–I—I—I–H–H–I—H–I—I—H–H–I—I—I—H–H–AuËŒ=ËŒ=À5Ã5À5À5À5À5€5À5Ã5À5Ã5À5Ã5Ã5À5À5dž:Ê‹=—lR! #~Œ€T>j§Zf§We¦Va¥S`¥Q]¤OZ¤LZ¤K@‡b;wi=ua=ua=ua=uanògž÷l¢÷q¥ø,¤Ž,£‚±øˆµùŒ·ù‘»ú,£Ž,£¦Éû«ÌûÏþ2¢ú#”÷4@egdc$sÕ$•ø;kñc›÷gžöm£ø,£Ž,¤°ù‚±ø‡µùŒ¸ù,£,£¡Æú¨ÊûšÌü1¢ú$•ø4@egdc%sÖ#•÷:jñ_™÷c›ögž÷"=´,£ 9´y«ø¯ù‚±ø‡µù!:´,£ 9´›Âú¢Çû–Êü1¢ù#•÷5@fgdc%tÖ$•ø8iñZ•ö_™÷cœ÷gžöm¢÷q¥øv©ø{¬ø¯ø„³ù‡´ùŽºú‘»ù˜ÀúœÂú“Çû1¡ù#”÷5Afgdc$sÕ$•ø0[ñFóHóLƒóQ†ôS‡ôY‹õ[õ_õa‘õe“öh•õj—öo›öqœöuŸöm¢÷.™ø#”÷5@egdc%sÖ$•÷$€õ$€õ#ô#€õ#€õ$€õ#€õ$€õ$€õ$€õ$€õ#€ô$€õ#€õ#€õ$€õ#ô#•÷$•ø5@fgdc8wÐ#”÷#•÷$•ø$•÷#•÷$•ø#”÷$•ø$•ø$•ø#•÷#”÷$•ø#”÷#•÷$•ø$•ø#”÷#”÷$•øXf‘\{Äéõÿéõÿéõÿáðÿ×ìÿÌæþÅâþ¹Ýÿ³Úÿ§Ôþ Ñþ–ÌýÇý†Ãü|¿ýv»ük¶ük¶üh€¸\{Äéõÿéõÿèôÿáðÿ×ëÿÌæÿÅâþ¹Ýÿ²Ùþ§Õÿ Ñþ–ÌýŒÇý†Ãüq¸üv»üh€¸\{ÄéõÿäòÿèôÿÞïÿ×ëÿÊåþÅâþ¹Ýþ²Ùþ§Õþ Òþ–ÌýŒÇý†Ãüh€¸\{Ä…£ØxÙxÙt›Ùt›Ùq™Ùo™Ùm—Øm—Ùk–Ùk–Ùk–Ùh€¸ÿÿÿÿÿÿðàÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀàðø?üþÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿð?ÿÿøÿÿüÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿ( @ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ( ³G—I¡=J¡=I¡=I¡=I¡=_s-ÌIÒ˜XÒ˜XÒ™YÒ˜XÒ™Y¦|Xfdc“¾d`¦Ñ©;w ÎåÐÜíÞËîà_s-ÔždëÈ”©d7©d6ðÛÇøëÞ«Zgec”¾‘]šU™Ëœ;w ¹Û½ÍåиãÎ_s-ÓœY¨c6¼Zݰ„Ê”rôâË«Zfdc”¾‘X˜O†Á„;w _s-LJ)Ñ–9Ò—<Ô›QÓœYÓže®ƒ\°®¬ÕÚÖƒ–…²Ô¹v¦ ,i»;z¯;z¯;z¯;z° // MFC core and standard components #include // MFC extensions #include // MFC Automation classes #include // MFC support for Internet Explorer 4 Common Controls #ifndef _AFX_NO_AFXCMN_SUPPORT #include // MFC support for Windows Common Controls #endif // _AFX_NO_AFXCMN_SUPPORT #include // MFC socket extensions stund/WinStun/WinStun.rc0000644000175000017500000001222611710231326013352 0ustar kkkk// Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "afxres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (U.S.) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #ifdef _WIN32 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) #endif //_WIN32 #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""afxres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "#define _AFX_NO_SPLITTER_RESOURCES\r\n" "#define _AFX_NO_OLE_RESOURCES\r\n" "#define _AFX_NO_TRACKER_RESOURCES\r\n" "#define _AFX_NO_PROPERTY_RESOURCES\r\n" "\r\n" "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" "LANGUAGE 9, 1\r\n" "#pragma code_page(1252)\r\n" "#include ""res\\WinStun.rc2"" // non-Microsoft Visual C++ edited resources\r\n" "#include ""afxres.rc"" // Standard components\r\n" "#endif\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDR_MAINFRAME ICON "res\\WinStun.ico" ///////////////////////////////////////////////////////////////////////////// // // Dialog // IDD_ABOUTBOX DIALOGEX 0, 0, 235, 55 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "About WinStun" FONT 8, "MS Shell Dlg", 0, 0, 0x1 BEGIN ICON IDR_MAINFRAME,IDC_STATIC,11,17,20,20 LTEXT "WinStun Version 0.94",IDC_STATIC,40,10,119,8, SS_NOPREFIX LTEXT "Cullen Jennings",IDC_STATIC,40,25,119,8 DEFPUSHBUTTON "OK",IDOK,178,7,50,16,WS_GROUP END IDD_WINSTUN_DIALOG DIALOGEX 0, 0, 209, 129 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_APPWINDOW CAPTION "WinStun" FONT 8, "MS Shell Dlg", 0, 0, 0x1 BEGIN PUSHBUTTON "Quit",IDCANCEL,116,106,50,16 PUSHBUTTON "Run Test",IDC_TEST,19,108,50,14 LTEXT "Stun Server",IDC_STATIC,7,7,39,8 EDITTEXT IDC_SERVER,48,7,142,12,ES_AUTOHSCROLL EDITTEXT IDC_RESULT,7,24,190,77,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | WS_VSCROLL | NOT WS_TABSTOP, WS_EX_STATICEDGE END ///////////////////////////////////////////////////////////////////////////// // // Version // VS_VERSION_INFO VERSIONINFO FILEVERSION 0,94,0,0 PRODUCTVERSION 0,94,0,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x4L FILETYPE 0x1L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904e4" BEGIN VALUE "FileDescription", "STUN Client" VALUE "FileVersion", "0, 94, 0, 0" VALUE "InternalName", "WinStun.exe" VALUE "OriginalFilename", "WinStun.exe" VALUE "ProductName", "WinStun" VALUE "ProductVersion", "0.94.0.0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1252 END END ///////////////////////////////////////////////////////////////////////////// // // DESIGNINFO // #ifdef APSTUDIO_INVOKED GUIDELINES DESIGNINFO BEGIN IDD_ABOUTBOX, DIALOG BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 228 TOPMARGIN, 7 BOTTOMMARGIN, 48 END IDD_WINSTUN_DIALOG, DIALOG BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 202 TOPMARGIN, 7 BOTTOMMARGIN, 122 END END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // RT_MANIFEST // IDR_MANIFEST RT_MANIFEST "res\\WinStun.manifest" ///////////////////////////////////////////////////////////////////////////// // // String Table // STRINGTABLE BEGIN IDS_ABOUTBOX "&About WinStun..." IDP_SOCKETS_INIT_FAILED "Windows sockets initialization failed." END #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // #define _AFX_NO_SPLITTER_RESOURCES #define _AFX_NO_OLE_RESOURCES #define _AFX_NO_TRACKER_RESOURCES #define _AFX_NO_PROPERTY_RESOURCES #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) LANGUAGE 9, 1 #pragma code_page(1252) #include "res\WinStun.rc2" // non-Microsoft Visual C++ edited resources #include "afxres.rc" // Standard components #endif ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED stund/client.sln0000644000175000017500000000157311710231326012005 0ustar kkkkMicrosoft Visual Studio Solution File, Format Version 7.00 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "client", "client.vcproj", "{76E56991-C964-444B-82A6-AFDA5145E18A}" EndProject Global GlobalSection(SolutionConfiguration) = preSolution ConfigName.0 = Debug ConfigName.1 = Release EndGlobalSection GlobalSection(ProjectDependencies) = postSolution EndGlobalSection GlobalSection(ProjectConfiguration) = postSolution {76E56991-C964-444B-82A6-AFDA5145E18A}.Debug.ActiveCfg = Debug|Win32 {76E56991-C964-444B-82A6-AFDA5145E18A}.Debug.Build.0 = Debug|Win32 {76E56991-C964-444B-82A6-AFDA5145E18A}.Release.ActiveCfg = Release|Win32 {76E56991-C964-444B-82A6-AFDA5145E18A}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection GlobalSection(ExtensibilityAddIns) = postSolution EndGlobalSection EndGlobal stund/root.pem0000644000175000017500000000230411710231326011470 0ustar kkkk-----BEGIN CERTIFICATE----- MIIDWTCCAsKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBgDELMAkGA1UEBhMCVUEx CzAJBgNVBAgTAkNBMREwDwYDVQQHEwhNaWxwaXRhczEOMAwGA1UEChMFRm9vQ28x EzARBgNVBAsTCndpZGdldCBkaXYxEjAQBgNVBAMTCWxvY2FsaG9zdDEYMBYGCSqG SIb3DQEJARYJZm9vQGZvby5jMB4XDTAyMTEwMTAzMDUwOFoXDTAyMTIwMTAzMDUw OFowgYAxCzAJBgNVBAYTAlVBMQswCQYDVQQIEwJDQTERMA8GA1UEBxMITWlscGl0 YXMxDjAMBgNVBAoTBUZvb0NvMRMwEQYDVQQLEwp3aWRnZXQgZGl2MRIwEAYDVQQD Ewlsb2NhbGhvc3QxGDAWBgkqhkiG9w0BCQEWCWZvb0Bmb28uYzCBnzANBgkqhkiG 9w0BAQEFAAOBjQAwgYkCgYEAwgvATkHnZzuN3poEtJ+l3p8rWlRVN4QnT4hW/pxI kZgs+U3/2QX2HZtGBcm+YJCfAICWdsnMDwhPlyp/YXdpyhe2wkl1LdukvMav8j+H shEQdcO+qPrjUZ8VLkMsMxM56b+UNT1m3CEoQ3qnIGuIb0DjvwfJRaiTo15LZv5j 1wkCAwEAAaOB4DCB3TAdBgNVHQ4EFgQUlnqNTIdfldOWBuAsqXVxr8OB4p4wga0G A1UdIwSBpTCBooAUlnqNTIdfldOWBuAsqXVxr8OB4p6hgYakgYMwgYAxCzAJBgNV BAYTAlVBMQswCQYDVQQIEwJDQTERMA8GA1UEBxMITWlscGl0YXMxDjAMBgNVBAoT BUZvb0NvMRMwEQYDVQQLEwp3aWRnZXQgZGl2MRIwEAYDVQQDEwlsb2NhbGhvc3Qx GDAWBgkqhkiG9w0BCQEWCWZvb0Bmb28uY4IBADAMBgNVHRMEBTADAQH/MA0GCSqG SIb3DQEBBAUAA4GBAC0j/qC+PRfpIRwISxQALNm/HPtIFbQDNFwYBfVgxxQOm9cT gP1S9zRU8Z6K7E0ZYu6VvZAzuY9qOJK4M6X0gdGlx60QqR7poAnFiWtUtrWzs6YS M6ZGUjSXnnqMkP1vauvbmV72CdYLR9dIQ6OMQqJ6GKznOGJd0hW8nHzhvBUh -----END CERTIFICATE----- stund/client.cxx0000644000175000017500000002635711710231326012022 0ustar kkkk#include #include #include #include #ifdef WIN32 #include #else #include #include #include #include #include #endif #include "udp.h" #include "stun.h" using namespace std; void usage() { cerr << "Usage:" << endl << " ./client stunServerHostname [testNumber] [-v] [-p srcPort] [-i nicAddr1] [-i nicAddr2] [-i nicAddr3]" << endl << "For example, if the STUN server was larry.gloo.net, you could do:" << endl << " ./client larry.gloo.net" << endl << "The testNumber is just used for special tests." << endl << " test 1 runs test 1 from the RFC. For example:" << endl << " ./client larry.gloo.net 0" << endl << endl << endl; } #define MAX_NIC 3 int main(int argc, char* argv[]) { assert( sizeof(UInt8 ) == 1 ); assert( sizeof(UInt16) == 2 ); assert( sizeof(UInt32) == 4 ); initNetwork(); cout << "STUN client version " << STUN_VERSION << endl; int testNum = 0; bool verbose = false; StunAddress4 stunServerAddr; stunServerAddr.addr=0; int srcPort=0; StunAddress4 sAddr[MAX_NIC]; int retval[MAX_NIC]; int numNic=0; for ( int i=0; i= MAX_NIC ) { cerr << "Can not have more than "<< MAX_NIC <<" -i options" << endl; usage(); exit(-1); } stunParseServerName(argv[arg], sAddr[numNic++]); } else if ( !strcmp( argv[arg] , "-p" ) ) { arg++; if ( argc <= arg ) { usage(); exit(-1); } srcPort = strtol( argv[arg], NULL, 10); } else { char* ptr; int t = strtol( argv[arg], &ptr, 10 ); if ( *ptr == 0 ) { // conversion worked testNum = t; cout << "running test number " << testNum << endl; } else { bool ret = stunParseServerName( argv[arg], stunServerAddr); if ( ret != true ) { cerr << argv[arg] << " is not a valid host name " << endl; usage(); exit(-1); } } } } if ( srcPort == 0 ) { srcPort = stunRandomPort(); } if ( numNic == 0 ) { // use default numNic = 1; } for ( int nic=0; nic=0; i-- ) { if ( retval[i] == -1 ) { ret = 0xFFFFFFFF; break; } ret = ret << 8; ret = ret | ( retval[i] & 0xFF ); } cout << "Return value is " << hex << "0x"; cout.fill('0'); cout.width(6); cout << ret << dec << endl; cout.fill(' '); return ret; } /* ==================================================================== * The Vovida Software License, Version 1.0 * * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The names "VOCAL", "Vovida Open Communication Application Library", * and "Vovida Open Communication Application Library (VOCAL)" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact vocal@vovida.org. * * 4. Products derived from this software may not be called "VOCAL", nor * may "VOCAL" appear in their name, without prior written * permission of Vovida Networks, Inc. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * * ==================================================================== * * This software consists of voluntary contributions made by Vovida * Networks, Inc. and many individuals on behalf of Vovida Networks, * Inc. For more information on Vovida Networks, Inc., please see * . * */ // Local Variables: // mode:c++ // c-file-style:"ellemtel" // c-file-offsets:((case-label . +)) // indent-tabs-mode:nil // End: stund/udp.h0000644000175000017500000001230511710231326010745 0ustar kkkk#ifndef udp_h #define udp_h #ifdef __MACH__ typedef int socklen_t; #endif #include #ifdef WIN32 #include #include typedef int socklen_t; typedef SOCKET Socket; #define EWOULDBLOCK WSAEWOULDBLOCK #define EINPROGRESS WSAEINPROGRESS #define EALREADY WSAEALREADY #define ENOTSOCK WSAENOTSOCK #define EDESTADDRREQ WSAEDESTADDRREQ #define EMSGSIZE WSAEMSGSIZE #define EPROTOTYPE WSAEPROTOTYPE #define ENOPROTOOPT WSAENOPROTOOPT #define EPROTONOSUPPORT WSAEPROTONOSUPPORT #define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT #define EOPNOTSUPP WSAEOPNOTSUPP #define EPFNOSUPPORT WSAEPFNOSUPPORT #define EAFNOSUPPORT WSAEAFNOSUPPORT #define EADDRINUSE WSAEADDRINUSE #define EADDRNOTAVAIL WSAEADDRNOTAVAIL #define ENETDOWN WSAENETDOWN #define ENETUNREACH WSAENETUNREACH #define ENETRESET WSAENETRESET #define ECONNABORTED WSAECONNABORTED #define ECONNRESET WSAECONNRESET #define ENOBUFS WSAENOBUFS #define EISCONN WSAEISCONN #define ENOTCONN WSAENOTCONN #define ESHUTDOWN WSAESHUTDOWN #define ETOOMANYREFS WSAETOOMANYREFS #define ETIMEDOUT WSAETIMEDOUT #define ECONNREFUSED WSAECONNREFUSED #define ELOOP WSAELOOP #define EHOSTDOWN WSAEHOSTDOWN #define EHOSTUNREACH WSAEHOSTUNREACH #define EPROCLIM WSAEPROCLIM #define EUSERS WSAEUSERS #define EDQUOT WSAEDQUOT #define ESTALE WSAESTALE #define EREMOTE WSAEREMOTE typedef LONGLONG Int64; inline int getErrno() { return WSAGetLastError(); } #else typedef int Socket; static const Socket INVALID_SOCKET = -1; static const int SOCKET_ERROR = -1; inline int closesocket( Socket fd ) { return close(fd); }; inline int getErrno() { return errno; } #define WSANOTINITIALISED EPROTONOSUPPORT #endif /// Open a UDP socket to receive on the given port - if port is 0, pick a a /// port, if interfaceIp!=0 then use ONLY the interface specified instead of /// all of them Socket openPort( unsigned short port, unsigned int interfaceIp, bool verbose); /// recive a UDP message bool getMessage( Socket fd, char* buf, int* len, unsigned int* srcIp, unsigned short* srcPort, bool verbose); /// send a UDP message bool sendMessage( Socket fd, char* msg, int len, unsigned int dstIp, unsigned short dstPort, bool verbose); /// set up network - does nothing in unix but needed for windows void initNetwork(); /* ==================================================================== * The Vovida Software License, Version 1.0 * * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The names "VOCAL", "Vovida Open Communication Application Library", * and "Vovida Open Communication Application Library (VOCAL)" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact vocal@vovida.org. * * 4. Products derived from this software may not be called "VOCAL", nor * may "VOCAL" appear in their name, without prior written * permission of Vovida Networks, Inc. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * * ==================================================================== * * This software consists of voluntary contributions made by Vovida * Networks, Inc. and many individuals on behalf of Vovida Networks, * Inc. For more information on Vovida Networks, Inc., please see * . * */ // Local Variables: // mode:c++ // c-file-style:"ellemtel" // c-file-offsets:((case-label . +)) // indent-tabs-mode:nil // End: #endif stund/server.cxx0000644000175000017500000001665011710231326012045 0ustar kkkk#include #include #include #include #ifndef WIN32 #include #include #include #include #include #include #endif #include "udp.h" #include "stun.h" using namespace std; void usage() { cerr << "Usage: " << endl << " ./server [-v] [-h] [-h IP_Address] [-a IP_Address] [-p port] [-o port] [-m mediaport]" << endl << " " << endl << " If the IP addresses of your NIC are 10.0.1.150 and 10.0.1.151, run this program with" << endl << " ./server -v -h 10.0.1.150 -a 10.0.1.151" << endl << " STUN servers need two IP addresses and two ports, these can be specified with:" << endl << " -h sets the primary IP" << endl << " -a sets the secondary IP" << endl << " -p sets the primary port and defaults to 3478" << endl << " -o sets the secondary port and defaults to 3479" << endl << " -b makes the program run in the backgroud" << endl << " -m sets up a STERN server starting at port m" << endl << " -v runs in verbose mode" << endl // in makefile too << endl; } int main(int argc, char* argv[]) { assert( sizeof(UInt8 ) == 1 ); assert( sizeof(UInt16) == 2 ); assert( sizeof(UInt32) == 4 ); initNetwork(); clog << "STUN server version " << STUN_VERSION << endl; StunAddress4 myAddr; StunAddress4 altAddr; bool verbose=false; bool background=false; myAddr.addr = 0; altAddr.addr = 0; myAddr.port = STUN_PORT; altAddr.port = STUN_PORT+1; int myPort = 0; int altPort = 0; int myMediaPort = 0; UInt32 interfaces[10]; int numInterfaces = stunFindLocalInterfaces(interfaces,10); if (numInterfaces == 2) { myAddr.addr = interfaces[0]; myAddr.port = STUN_PORT; altAddr.addr = interfaces[1]; altAddr.port = STUN_PORT+1; } for ( int arg = 1; arg. * */ // Local Variables: // mode:c++ // c-file-style:"ellemtel" // c-file-offsets:((case-label . +)) // indent-tabs-mode:nil // End: stund/WinStunSetup/0000755000175000017500000000000012445636075012453 5ustar kkkkstund/WinStunSetup/WinStunSetup.vdproj0000644000175000017500000007660611710231325016327 0ustar kkkk"DeployProject" { "VSVersion" = "3:700" "ProjectType" = "8:{5443560c-dbb4-11d2-8724-00a0c9a8b90c}" "IsWebType" = "8:FALSE" "ProjectName" = "8:WinStunSetup" "LanguageId" = "3:1033" "CodePage" = "3:1252" "UILanguageId" = "3:1033" "SccProjectName" = "8:" "SccLocalPath" = "8:" "SccAuxPath" = "8:" "SccProvider" = "8:" "Hierarchy" { "Entry" { "MsmKey" = "8:_09250952BF7CDB5CAADD71B62AF74DB4" "OwnerKey" = "8:_F6B936BEEBCC457AA39994BB0B8A53A5" "MsmSig" = "8:C:\\WINDOWS\\SYSTEM32\\WSOCK32.DLL" } "Entry" { "MsmKey" = "8:_17F9ABD901D5439A842383FF8C1C7785" "OwnerKey" = "8:_F6B936BEEBCC457AA39994BB0B8A53A5" "MsmSig" = "8:VC_User_STL.BA9B76E9_0DE0_11D5_A548_0090278A1BB8" } "Entry" { "MsmKey" = "8:_816BB8A582964A2AA373F9ACE0C3CC04" "OwnerKey" = "8:_F6B936BEEBCC457AA39994BB0B8A53A5" "MsmSig" = "8:VC_User_MFC.BA9B6D6E_0DE0_11D5_A548_0090278A1BB8" } "Entry" { "MsmKey" = "8:_A68BA668DD6C41F2B5DF639071F18F86" "OwnerKey" = "8:_F6B936BEEBCC457AA39994BB0B8A53A5" "MsmSig" = "8:VC_User_CRT.BA9B6D09_0DE0_11D5_A548_0090278A1BB8" } "Entry" { "MsmKey" = "8:_F6B936BEEBCC457AA39994BB0B8A53A5" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:C:\\VOCAL\\STUND\\WINSTUN\\DEBUG\\WINSTUN.EXE" } } "Configurations" { "Debug" { "DisplayName" = "8:Debug" "IsDebugOnly" = "11:TRUE" "IsReleaseOnly" = "11:FALSE" "OutputFilename" = "8:Debug\\WinStunSetup.msi" "PackageFilesAs" = "3:2" "PackageFileSize" = "3:-2147483648" "CabType" = "3:1" "Compression" = "3:2" "SignOutput" = "11:FALSE" "CertificateFile" = "8:" "PrivateKeyFile" = "8:" "TimeStampServer" = "8:" "InstallerBootstrapper" = "3:2" } "Release" { "DisplayName" = "8:Release" "IsDebugOnly" = "11:FALSE" "IsReleaseOnly" = "11:TRUE" "OutputFilename" = "8:Release\\WinStunSetup.msi" "PackageFilesAs" = "3:2" "PackageFileSize" = "3:-2147483648" "CabType" = "3:1" "Compression" = "3:3" "SignOutput" = "11:FALSE" "CertificateFile" = "8:" "PrivateKeyFile" = "8:" "TimeStampServer" = "8:" "InstallerBootstrapper" = "3:2" } } "Deployable" { "CustomAction" { } "DefaultFeature" { "Name" = "8:DefaultFeature" "Title" = "8:" "Description" = "8:" } "Feature" { } "File" { "{54DA9790-1474-11D3-8E00-00C04F6837D0}:_09250952BF7CDB5CAADD71B62AF74DB4" { "Signature" = "8:2000000000e0230e7df7c20142fec07abdbec4010033ad96f879c40100000000005800000000000000000000770073006f0063006b00330032002e0064006c006c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" "SourcePath" = "8:WSOCK32.dll" "TargetName" = "8:WSOCK32.dll" "Tag" = "8:" "Folder" = "8:_1ACFCA01E86242009E7DA340371B556E" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:TRUE" "IsDependency" = "11:TRUE" "IsolateTo" = "8:" } } "FileType" { } "Folder" { "{EE62640D-12F2-11D3-8D6C-00A0C9CFCEE6}:_1ACFCA01E86242009E7DA340371B556E" { "DefaultLocation" = "8:[ProgramFilesFolder][Manufacturer]\\[ProductName]" "Name" = "8:#1925" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:TARGETDIR" "Folders" { } } "{777C097F-0ED8-11D3-8D6C-00A0C9CFCEE6}:_9F73FB694078487ABBE751685A98BAE5" { "Name" = "8:#1919" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:ProgramMenuFolder" "Folders" { } } "{777C097F-0ED8-11D3-8D6C-00A0C9CFCEE6}:_CD285AFD3A9A4AF09C71F647BCB5F55F" { "Name" = "8:#1916" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:DesktopFolder" "Folders" { } } } "LaunchCondition" { } "Locator" { } "Shortcut" { "{D0C99CFE-1238-11D3-8E00-00C04F6837D0}:_9DD31FDA83A043F7A0E558517B5725D3" { "Name" = "8:WinSTUN" "Arguments" = "8:" "Description" = "8:" "ShowCmd" = "3:1" "IconIndex" = "3:0" "Transitive" = "11:FALSE" "Target" = "8:_F6B936BEEBCC457AA39994BB0B8A53A5" "Folder" = "8:_9F73FB694078487ABBE751685A98BAE5" "WorkingFolder" = "8:_1ACFCA01E86242009E7DA340371B556E" "Icon" = "8:" "Feature" = "8:" } } "Sequences" { } "Registry" { "HKLM" { "Keys" { "{7DF0CD0A-FF27-11D2-8D6B-00A0C9CFCEE6}:_40E4B8C97A03455C8DF5FA68455B929E" { "Name" = "8:Software" "Condition" = "8:" "AlwaysCreate" = "11:FALSE" "DeleteAtUninstall" = "11:FALSE" "Transitive" = "11:FALSE" "Keys" { "{7DF0CD0A-FF27-11D2-8D6B-00A0C9CFCEE6}:_50DC98EDDEAB4F63A5B6A17D733642C2" { "Name" = "8:[Manufacturer]" "Condition" = "8:" "AlwaysCreate" = "11:FALSE" "DeleteAtUninstall" = "11:FALSE" "Transitive" = "11:FALSE" "Keys" { } "Values" { } } } "Values" { } } } } "HKCU" { "Keys" { "{7DF0CD0A-FF27-11D2-8D6B-00A0C9CFCEE6}:_D404EAC782F44270A6D873736C45FB23" { "Name" = "8:Software" "Condition" = "8:" "AlwaysCreate" = "11:FALSE" "DeleteAtUninstall" = "11:FALSE" "Transitive" = "11:FALSE" "Keys" { "{7DF0CD0A-FF27-11D2-8D6B-00A0C9CFCEE6}:_221FC41A7DD547B182BD9DE45E0E8EB2" { "Name" = "8:[Manufacturer]" "Condition" = "8:" "AlwaysCreate" = "11:FALSE" "DeleteAtUninstall" = "11:FALSE" "Transitive" = "11:FALSE" "Keys" { } "Values" { } } } "Values" { } } } } "HKCR" { "Keys" { } } "HKU" { "Keys" { } } "HKPU" { "Keys" { } } } "ProjectOutput" { "{B1E2BB22-187D-11D3-8E02-00C04F6837D0}:_F6B936BEEBCC457AA39994BB0B8A53A5" { "SourcePath" = "8:..\\WinStun\\Debug\\WinStun.exe" "TargetName" = "8:" "Tag" = "8:" "Folder" = "8:_1ACFCA01E86242009E7DA340371B556E" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" "ProjectOutputGroupRegister" = "3:1" "OutputConfiguration" = "8:" "OutputGroupCanonicalName" = "8:Built" "OutputProjectCanonicalName" = "8:WinStun\\WinStun.vcproj" "OutputProjectGuid" = "8:{717021E7-DCC4-41E7-9CDA-FA7596F18C56}" "ShowKeyOutput" = "11:TRUE" "ExcludeFilters" { } } } "Product" { "Name" = "8:Microsoft Visual Studio" "ProductName" = "8:WinStun" "ProductCode" = "8:{B7E2AB75-61C8-4DB6-9456-20BDAAB8732D}" "PackageCode" = "8:{5A8E9898-1599-4F05-9B2C-1B57017673DB}" "UpgradeCode" = "8:{2F0F50F5-2556-4068-8E05-1BDCCFBF66D7}" "RestartWWWService" = "11:FALSE" "RemovePreviousVersions" = "11:TRUE" "DetectNewerInstalledVersion" = "11:TRUE" "ProductVersion" = "8:0.94" "Manufacturer" = "8:fluffy" "ARPHELPTELEPHONE" = "8:" "ARPHELPLINK" = "8:www.vovida.org" "Title" = "8:WinStun" "Subject" = "8:" "ARPCONTACT" = "8:fluffy" "Keywords" = "8:Stun" "ARPCOMMENTS" = "8:Stun Test Program" "ARPURLINFOABOUT" = "8:" "ARPPRODUCTICON" = "8:" "ARPIconIndex" = "3:0" "SearchPath" = "8:" "UseSystemSearchPath" = "11:TRUE" } "MsiBootstrapper" { "LangId" = "3:1033" } "MergeModule" { "{AC8774A4-3E09-11D3-8E14-00C04F6837D0}:_17F9ABD901D5439A842383FF8C1C7785" { "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:TRUE" "SourcePath" = "8:vc_stl.msm" "ModuleSignature" = "8:VC_User_STL.BA9B76E9_0DE0_11D5_A548_0090278A1BB8" "Properties" { "DIR_RETARGET_TARGETDIR" { "Name" = "8:DIR_RETARGET_TARGETDIR" "DisplayName" = "8:Module Retargetable Folder" "Description" = "8:" "Type" = "3:10" "ContextData" = "8:IsolationDir" "Attributes" = "3:6" "Setting" = "3:1" "UsePlugInResources" = "11:FALSE" } } "LanguageId" = "3:0" "Exclude" = "11:FALSE" "Folder" = "8:" "Feature" = "8:" "IsolateTo" = "8:" } "{AC8774A4-3E09-11D3-8E14-00C04F6837D0}:_816BB8A582964A2AA373F9ACE0C3CC04" { "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:TRUE" "SourcePath" = "8:vc_mfc.msm" "ModuleSignature" = "8:VC_User_MFC.BA9B6D6E_0DE0_11D5_A548_0090278A1BB8" "Properties" { "DIR_RETARGET_TARGETDIR" { "Name" = "8:DIR_RETARGET_TARGETDIR" "DisplayName" = "8:Module Retargetable Folder" "Description" = "8:" "Type" = "3:10" "ContextData" = "8:IsolationDir" "Attributes" = "3:6" "Setting" = "3:1" "UsePlugInResources" = "11:FALSE" } } "LanguageId" = "3:0" "Exclude" = "11:FALSE" "Folder" = "8:" "Feature" = "8:" "IsolateTo" = "8:" } "{AC8774A4-3E09-11D3-8E14-00C04F6837D0}:_A68BA668DD6C41F2B5DF639071F18F86" { "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:TRUE" "SourcePath" = "8:vc_crt.msm" "ModuleSignature" = "8:VC_User_CRT.BA9B6D09_0DE0_11D5_A548_0090278A1BB8" "Properties" { "DIR_RETARGET_TARGETDIR" { "Name" = "8:DIR_RETARGET_TARGETDIR" "DisplayName" = "8:Module Retargetable Folder" "Description" = "8:" "Type" = "3:10" "ContextData" = "8:IsolationDir" "Attributes" = "3:6" "Setting" = "3:1" "UsePlugInResources" = "11:FALSE" } } "LanguageId" = "3:0" "Exclude" = "11:FALSE" "Folder" = "8:" "Feature" = "8:" "IsolateTo" = "8:" } } "UserInterface" { "{E4ECAB26-4AB7-11D3-8D78-00A0C9CFCEE6}:_309D912E287A4301B573A2B8BF79CA47" { "UseDynamicProperties" = "11:FALSE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdBasicDialogs.wim" "ModuleSignature" = "8:VsdDialogs.CE4B864F_F1C1_4B85_98D4_2A2BF5FFB12B" } "{7DFFC192-4ABE-11D3-8D78-00A0C9CFCEE6}:_3AAC016866E5446D98CAA124E4E70365" { "Name" = "8:#1900" "Sequence" = "3:2" "Attributes" = "3:1" "Dialogs" { "{E4ECAB24-4AB7-11D3-8D78-00A0C9CFCEE6}:_6453CD704CE541EDB46A6A6F40AD5B11" { "Sequence" = "3:100" "DisplayName" = "8:Welcome" "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdAdminWelcomeDlg.wid" "ModuleSignature" = "8:VsdDialogs.E35A0E2C_F131_4B57_B946_59A1A2A8F45F" "Properties" { "BannerBitmap" { "Name" = "8:BannerBitmap" "DisplayName" = "8:#1001" "Description" = "8:#1101" "Type" = "3:8" "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:1" "UsePlugInResources" = "11:TRUE" } "CopyrightWarning" { "Name" = "8:CopyrightWarning" "DisplayName" = "8:#1002" "Description" = "8:#1102" "Type" = "3:3" "ContextData" = "8:" "Attributes" = "3:0" "Setting" = "3:1" "Value" = "8:#1202" "DefaultValue" = "8:#1202" "UsePlugInResources" = "11:TRUE" } "Welcome" { "Name" = "8:Welcome" "DisplayName" = "8:#1003" "Description" = "8:#1103" "Type" = "3:3" "ContextData" = "8:" "Attributes" = "3:0" "Setting" = "3:1" "Value" = "8:#1203" "DefaultValue" = "8:#1203" "UsePlugInResources" = "11:TRUE" } } } "{E4ECAB24-4AB7-11D3-8D78-00A0C9CFCEE6}:_8866EC8182F44659BA8DB0975A01235C" { "Sequence" = "3:200" "DisplayName" = "8:Installation Folder" "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdAdminFolderDlg.wid" "ModuleSignature" = "8:VsdDialogs.2DED2424_5429_4616_A1AD_4D62837C2ADA" "Properties" { "BannerBitmap" { "Name" = "8:BannerBitmap" "DisplayName" = "8:#1001" "Description" = "8:#1101" "Type" = "3:8" "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:1" "UsePlugInResources" = "11:TRUE" } } } "{E4ECAB24-4AB7-11D3-8D78-00A0C9CFCEE6}:_93025AA9E4EB456B92CEA130A0F3BCF4" { "Sequence" = "3:300" "DisplayName" = "8:Confirm Installation" "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdAdminConfirmDlg.wid" "ModuleSignature" = "8:VsdDialogs.FA58E60A_A1E8_4876_95FC_2AC3B5AAA5F8" "Properties" { "BannerBitmap" { "Name" = "8:BannerBitmap" "DisplayName" = "8:#1001" "Description" = "8:#1101" "Type" = "3:8" "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:1" "UsePlugInResources" = "11:TRUE" } } } } } "{7DFFC192-4ABE-11D3-8D78-00A0C9CFCEE6}:_3EA2C9B465F54D72A7DDDFCC5621F1D0" { "Name" = "8:#1902" "Sequence" = "3:1" "Attributes" = "3:3" "Dialogs" { "{E4ECAB24-4AB7-11D3-8D78-00A0C9CFCEE6}:_16667F6AD73F471591FDCB7F4172769C" { "Sequence" = "3:100" "DisplayName" = "8:Finished" "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdFinishedDlg.wid" "ModuleSignature" = "8:VsdDialogs.1DB77F5A_BA5C_4470_89B6_0B0EC07E3A10" "Properties" { "BannerBitmap" { "Name" = "8:BannerBitmap" "DisplayName" = "8:#1001" "Description" = "8:#1101" "Type" = "3:8" "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:1" "UsePlugInResources" = "11:TRUE" } } } } } "{7DFFC192-4ABE-11D3-8D78-00A0C9CFCEE6}:_91E8D85BC8534AFE80406ED50E981274" { "Name" = "8:#1902" "Sequence" = "3:2" "Attributes" = "3:3" "Dialogs" { "{E4ECAB24-4AB7-11D3-8D78-00A0C9CFCEE6}:_8BD23B7A446C400F965A22995B56653C" { "Sequence" = "3:100" "DisplayName" = "8:Finished" "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdAdminFinishedDlg.wid" "ModuleSignature" = "8:VsdDialogs.83D22742_1B79_46f6_9A99_DF0F2BD4C077" "Properties" { "BannerBitmap" { "Name" = "8:BannerBitmap" "DisplayName" = "8:#1001" "Description" = "8:#1101" "Type" = "3:8" "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:1" "UsePlugInResources" = "11:TRUE" } } } } } "{7DFFC192-4ABE-11D3-8D78-00A0C9CFCEE6}:_A4071551ACF7452A8194ECACD3822A24" { "Name" = "8:#1901" "Sequence" = "3:2" "Attributes" = "3:2" "Dialogs" { "{E4ECAB24-4AB7-11D3-8D78-00A0C9CFCEE6}:_487DF826178549ADAA991554EE93AC62" { "Sequence" = "3:100" "DisplayName" = "8:Progress" "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdAdminProgressDlg.wid" "ModuleSignature" = "8:VsdDialogs.EE9A1AFA_41DD_4514_B727_DF0ACA1D7389" "Properties" { "BannerBitmap" { "Name" = "8:BannerBitmap" "DisplayName" = "8:#1001" "Description" = "8:#1101" "Type" = "3:8" "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:1" "UsePlugInResources" = "11:TRUE" } "ShowProgress" { "Name" = "8:ShowProgress" "DisplayName" = "8:#1009" "Description" = "8:#1109" "Type" = "3:5" "ContextData" = "8:1;True=1;False=0" "Attributes" = "3:0" "Setting" = "3:0" "Value" = "3:1" "DefaultValue" = "3:1" "UsePlugInResources" = "11:TRUE" } } } } } "{E4ECAB26-4AB7-11D3-8D78-00A0C9CFCEE6}:_B77D9D04895542BC9E437226DBC206BA" { "UseDynamicProperties" = "11:FALSE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdUserInterface.wim" "ModuleSignature" = "8:VsdUserInterface.524F4245_5254_5341_4C45_534153783400" } "{7DFFC192-4ABE-11D3-8D78-00A0C9CFCEE6}:_CB82D982E7E04D1BB99B02029BFF4BB4" { "Name" = "8:#1900" "Sequence" = "3:1" "Attributes" = "3:1" "Dialogs" { "{E4ECAB24-4AB7-11D3-8D78-00A0C9CFCEE6}:_1C9C413826E7442292BDADA01492608D" { "Sequence" = "3:200" "DisplayName" = "8:Installation Folder" "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdFolderDlg.wid" "ModuleSignature" = "8:VsdDialogs.C113BC36_2532_4D45_8099_4818B1133B2F" "Properties" { "BannerBitmap" { "Name" = "8:BannerBitmap" "DisplayName" = "8:#1001" "Description" = "8:#1101" "Type" = "3:8" "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:1" "UsePlugInResources" = "11:TRUE" } } } "{E4ECAB24-4AB7-11D3-8D78-00A0C9CFCEE6}:_9949CC0ADBD947A7B1C91226942F4FEE" { "Sequence" = "3:100" "DisplayName" = "8:Welcome" "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdWelcomeDlg.wid" "ModuleSignature" = "8:VsdDialogs.68F69290_BB7C_474E_A153_6679845F3DDF" "Properties" { "BannerBitmap" { "Name" = "8:BannerBitmap" "DisplayName" = "8:#1001" "Description" = "8:#1101" "Type" = "3:8" "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:1" "UsePlugInResources" = "11:TRUE" } "CopyrightWarning" { "Name" = "8:CopyrightWarning" "DisplayName" = "8:#1002" "Description" = "8:#1102" "Type" = "3:3" "ContextData" = "8:" "Attributes" = "3:0" "Setting" = "3:1" "Value" = "8:#1202" "DefaultValue" = "8:#1202" "UsePlugInResources" = "11:TRUE" } "Welcome" { "Name" = "8:Welcome" "DisplayName" = "8:#1003" "Description" = "8:#1103" "Type" = "3:3" "ContextData" = "8:" "Attributes" = "3:0" "Setting" = "3:1" "Value" = "8:#1203" "DefaultValue" = "8:#1203" "UsePlugInResources" = "11:TRUE" } } } "{E4ECAB24-4AB7-11D3-8D78-00A0C9CFCEE6}:_C35965DAA3654FD188EB3BE51C84178E" { "Sequence" = "3:300" "DisplayName" = "8:Confirm Installation" "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdConfirmDlg.wid" "ModuleSignature" = "8:VsdDialogs.6DBC9783_3677_4D68_8BF5_D749558A0AC1" "Properties" { "BannerBitmap" { "Name" = "8:BannerBitmap" "DisplayName" = "8:#1001" "Description" = "8:#1101" "Type" = "3:8" "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:1" "UsePlugInResources" = "11:TRUE" } } } } } "{7DFFC192-4ABE-11D3-8D78-00A0C9CFCEE6}:_F18016A4BE774D76B6D7D70741C9C574" { "Name" = "8:#1901" "Sequence" = "3:1" "Attributes" = "3:2" "Dialogs" { "{E4ECAB24-4AB7-11D3-8D78-00A0C9CFCEE6}:_4CBDFAD72B2541849D7DFA35D5E52B1F" { "Sequence" = "3:100" "DisplayName" = "8:Progress" "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdProgressDlg.wid" "ModuleSignature" = "8:VsdDialogs.4FB12620_0D15_42D0_8677_2766FFA6923F" "Properties" { "BannerBitmap" { "Name" = "8:BannerBitmap" "DisplayName" = "8:#1001" "Description" = "8:#1101" "Type" = "3:8" "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:1" "UsePlugInResources" = "11:TRUE" } "ShowProgress" { "Name" = "8:ShowProgress" "DisplayName" = "8:#1009" "Description" = "8:#1109" "Type" = "3:5" "ContextData" = "8:1;True=1;False=0" "Attributes" = "3:0" "Setting" = "3:0" "Value" = "3:1" "DefaultValue" = "3:1" "UsePlugInResources" = "11:TRUE" } } } } } } } }