* added DETERMINISTIC_SYMMETRIC NAT type to Connect Logic. (CBS_NETSTATE_EXCLUSIVENAT)

* added DETERMINISTIC_SYMMETRIC NAT to retroshare/rsconfig and NetStateBox.
 * added ExclusiveMode to udpStunner.
 * Tweaked UdpStunner ping logic.
 * added TCP_WAIT to Connect Logic.

NB: This stuff is still to be tested!



git-svn-id: http://svn.code.sf.net/p/retroshare/code/branches/v0.5-netupgrade@4440 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
drbob 2011-07-13 11:41:25 +00:00
parent d6938721b0
commit 85d232ff4f
8 changed files with 245 additions and 43 deletions

View File

@ -30,6 +30,7 @@
#include <sstream>
#define FAILED_WAIT_TIME (300) //(1800) // 30 minutes.
#define TCP_WAIT_TIME (60) // 1 minutes.
#define DIRECT_WAIT_TIME (60) // 1 minutes.
#define PROXY_WAIT_TIME (60) // 1 minutes.
#define RELAY_WAIT_TIME (60) // 1 minutes.
@ -64,6 +65,10 @@ std::string NetStateAsString(uint32_t netstate)
str = "StableNat";
break;
case CSB_NETSTATE_EXCLUSIVENAT:
str = "ExclusiveNat";
break;
case CSB_NETSTATE_FIREWALLED:
str = "Firewalled";
break;
@ -83,6 +88,10 @@ std::string StateAsString(uint32_t state)
str = "Start";
break;
case CSB_TCP_WAIT:
str = "TCP Wait";
break;
case CSB_DIRECT_ATTEMPT:
str = "Direct Attempt";
break;
@ -210,6 +219,10 @@ uint32_t convertNetStateToInternal(uint32_t netmode, uint32_t nattype)
{
connNet = CSB_NETSTATE_STABLENAT;
}
else if (nattype == RSNET_NATTYPE_DETERM_SYM)
{
connNet = CSB_NETSTATE_EXCLUSIVENAT;
}
else
{
connNet = CSB_NETSTATE_FIREWALLED;
@ -278,6 +291,7 @@ uint32_t PeerConnectStateBox::connectCb_direct()
switch(mState)
{
case CSB_DIRECT_ATTEMPT:
{
errorMsg(std::cerr, "mState == DIRECT_ATTEMPT", 0);
@ -325,13 +339,32 @@ uint32_t PeerConnectStateBox::connectCb_direct()
case CSB_START:
{
/* starting up the connection */
mState = CSB_DIRECT_ATTEMPT;
retval = CSB_ACTION_DIRECT_CONN | CSB_ACTION_DHT_PORT;
mState = CSB_TCP_WAIT;
retval = CSB_ACTION_TCP_CONN;
mStateTS = now;
mNoAttempts = 0;
}
break;
case CSB_TCP_WAIT:
{
/* if too soon */
if (now - mStateTS < TCP_WAIT_TIME)
{
/* same state */
retval = CSB_ACTION_WAIT;
}
else
{
/* try again */
mState = CSB_DIRECT_ATTEMPT;
retval = CSB_ACTION_DIRECT_CONN | CSB_ACTION_DHT_PORT;
mStateTS = now;
mNoAttempts = 0;
}
}
break;
case CSB_DIRECT_WAIT:
{
/* if too soon */
@ -430,7 +463,24 @@ uint32_t PeerConnectStateBox::connectCb_unreachable()
} /* FALLTHROUGH TO START CASE */
case CSB_START:
{
/* starting up the connection */
mState = CSB_TCP_WAIT;
retval = CSB_ACTION_WAIT; /* NO POINT TRYING A TCP_CONN */
mStateTS = now;
mNoAttempts = 0;
}
break;
case CSB_TCP_WAIT:
{
/* if too soon */
if (now - mStateTS < TCP_WAIT_TIME)
{
/* same state */
retval = CSB_ACTION_WAIT;
}
else
{
/* starting up the connection */
if (mState != CSB_NETSTATE_FIREWALLED)
{
@ -443,10 +493,12 @@ uint32_t PeerConnectStateBox::connectCb_unreachable()
stateMsg(std::cerr, "Firewalled => RELAY_ATTEMPT", 0);
mState = CSB_RELAY_ATTEMPT;
retval = CSB_ACTION_RELAY_CONN | CSB_ACTION_DHT_PORT;
}
mStateTS = now;
mNoAttempts = 0;
}
}
break;

View File

@ -29,21 +29,23 @@
/* a connect state box */
#define CSB_START 1
#define CSB_DIRECT_ATTEMPT 2
#define CSB_DIRECT_WAIT 3
#define CSB_PROXY_ATTEMPT 4
#define CSB_PROXY_WAIT 5
#define CSB_RELAY_ATTEMPT 6
#define CSB_RELAY_WAIT 7
#define CSB_REVERSE_WAIT 8
#define CSB_FAILED_WAIT 9
#define CSB_CONNECTED 10
#define CSB_TCP_WAIT 2
#define CSB_DIRECT_ATTEMPT 3
#define CSB_DIRECT_WAIT 4
#define CSB_PROXY_ATTEMPT 5
#define CSB_PROXY_WAIT 6
#define CSB_RELAY_ATTEMPT 7
#define CSB_RELAY_WAIT 8
#define CSB_REVERSE_WAIT 9
#define CSB_FAILED_WAIT 10
#define CSB_CONNECTED 11
#define CSB_NETSTATE_UNKNOWN 0
#define CSB_NETSTATE_FORWARD 1
#define CSB_NETSTATE_STABLENAT 2
#define CSB_NETSTATE_FIREWALLED 3
#define CSB_NETSTATE_EXCLUSIVENAT 3
#define CSB_NETSTATE_FIREWALLED 4
#define CSB_CONNECT_DIRECT 1
#define CSB_CONNECT_UNREACHABLE 2
@ -53,9 +55,10 @@
#define CSB_ACTION_MASK_PORT 0xff00
#define CSB_ACTION_WAIT 0x0001
#define CSB_ACTION_DIRECT_CONN 0x0002
#define CSB_ACTION_PROXY_CONN 0x0004
#define CSB_ACTION_RELAY_CONN 0x0008
#define CSB_ACTION_TCP_CONN 0x0002
#define CSB_ACTION_DIRECT_CONN 0x0004
#define CSB_ACTION_PROXY_CONN 0x0008
#define CSB_ACTION_RELAY_CONN 0x0010
#define CSB_ACTION_DHT_PORT 0x0100
#define CSB_ACTION_PROXY_PORT 0x0200

View File

@ -1546,8 +1546,8 @@ void p3NetMgr::updateNetStateBox_temporal()
}
#define NET_STUNNER_PERIOD_FAST (300) // default of Stunner.
#define NET_STUNNER_PERIOD_SLOW (300) // 5 minutes.
#define NET_STUNNER_PERIOD_FAST (-1) // default of Stunner.
#define NET_STUNNER_PERIOD_SLOW (180) // 3 minutes.
void p3NetMgr::updateNatSetting()
{

View File

@ -31,10 +31,22 @@ void pqiNetStateBox::setAddressStunProxy(struct sockaddr_in *addr, bool stable)
(addr->sin_port != mStunProxyAddr.sin_port))
{
if (addr->sin_addr.s_addr == mStunProxyAddr.sin_addr.s_addr)
{
if (mStunProxyStable != stable)
{
mStunProxySemiStable = true;
}
}
else
{
mStunProxySemiStable = false; // change of address - must trigger this again!
}
mStunProxySet = true;
mStunProxyStable = stable;
mStunProxyAddr = *addr;
mStatusOkay = false;
}
mStunProxyTS = time(NULL);
@ -168,6 +180,7 @@ void pqiNetStateBox::reset()
//struct sockaddr_in mStunDhtAddr;
mStunProxySet = false;
mStunProxySemiStable = false;
time_t mStunProxyTS = 0;
bool mStunProxyStable = false;
//struct sockaddr_in mStunProxyAddr;
@ -268,7 +281,30 @@ void pqiNetStateBox::determineNetworkState()
//mExtAddress = mStunDhtExtAddress;
//mExtAddrStable = false;
if (!mStunProxyStable)
if (mStunProxySemiStable)
{
/* I'm guessing this will be a common mode for modern NAT/Firewalls.
* a DETERMINISTIC SYMMETRIC NAT.... This is likely to be the
* next iteration on the RESTRICTED CONE firewall described below.
* If you Stun fast, it looks like a SYMMETRIC NAT, but if you let
* the NAT timeout, you get back your original port so it looks like
* a RESTRICTED CONE nat...
*
* This kind of NAT is passable, if you only attempt one connection at
* a time, and are careful about it!
*
* NB: The StunDht port will never get this mode.
* It has unsolicited traffic which triggers SYM mode
*
*/
mNetworkMode = RSNET_NETWORK_BEHINDNAT;
mNatTypeMode = RSNET_NATTYPE_DETERM_SYM;
mNatHoleMode = RSNET_NATHOLE_NONE;
mNetStateMode = RSNET_NETSTATE_WARNING_NATTED;
}
else if (!mStunProxyStable)
{
/* both unstable, Symmetric NAT, Firewalled, No UDP Hole */
mNetworkMode = RSNET_NETWORK_BEHINDNAT;
@ -316,7 +352,15 @@ void pqiNetStateBox::determineNetworkState()
//mExtAddrStable = true;
// Initial Fallback Guess at firewall state.
if (!mStunProxyStable)
if (mStunProxySemiStable)
{
/* must be a forwarded port/ext or something similar */
mNetworkMode = RSNET_NETWORK_BEHINDNAT;
mNatTypeMode = RSNET_NATTYPE_DETERM_SYM;
mNatHoleMode = RSNET_NATHOLE_FORWARDED;
mNetStateMode = RSNET_NETSTATE_GOOD;
}
else if (!mStunProxyStable)
{
/* must be a forwarded port/ext or something similar */
mNetworkMode = RSNET_NETWORK_BEHINDNAT;
@ -523,7 +567,8 @@ void pqiNetStateBox::workoutNetworkMode()
mConnectModes |= RSNET_CONNECT_RELAY_UDP;
if ((mNatTypeMode == RSNET_NATTYPE_RESTRICTED_CONE) ||
(mNatTypeMode == RSNET_NATTYPE_FULL_CONE))
(mNatTypeMode == RSNET_NATTYPE_FULL_CONE) ||
(mNatTypeMode == RSNET_NATTYPE_DETERM_SYM))
{
mConnectModes |= RSNET_CONNECT_PROXY_UDP;
}
@ -573,6 +618,9 @@ std::string NetStateNatTypeString(uint32_t natType)
case RSNET_NATTYPE_SYMMETRIC:
str = "SYMMETRIC NAT";
break;
case RSNET_NATTYPE_DETERM_SYM:
str = "DETERMINISTIC SYM NAT";
break;
case RSNET_NATTYPE_RESTRICTED_CONE:
str = "RESTRICTED CONE NAT";
break;

View File

@ -66,6 +66,7 @@ class pqiNetStateBox
bool mStunProxySet;
time_t mStunProxyTS;
bool mStunProxyStable;
bool mStunProxySemiStable;
struct sockaddr_in mStunProxyAddr;
bool mDhtSet;

View File

@ -49,9 +49,10 @@ extern RsServerConfig *rsConfig;
#define RSNET_NATTYPE_NONE 1
#define RSNET_NATTYPE_UNKNOWN 2
#define RSNET_NATTYPE_SYMMETRIC 3
#define RSNET_NATTYPE_RESTRICTED_CONE 4
#define RSNET_NATTYPE_FULL_CONE 5
#define RSNET_NATTYPE_OTHER 6
#define RSNET_NATTYPE_DETERM_SYM 4
#define RSNET_NATTYPE_RESTRICTED_CONE 5
#define RSNET_NATTYPE_FULL_CONE 6
#define RSNET_NATTYPE_OTHER 7
// WHAT TYPE OF HOLE?
#define RSNET_NATHOLE_UNKNOWN 0

View File

@ -65,6 +65,9 @@ UdpStunner::UdpStunner(UdpPublisher *pub)
mSuccessRate = 0.0;
mTargetStunPeriod = TOU_STUN_DEFAULT_TARGET_RATE;
mExclusiveMode = false;
mExclusiveModeTS = 0;
return;
}
@ -80,6 +83,76 @@ void UdpStunner::SetAcceptLocalNet()
#endif
int UdpStunner::setExclusiveMode() /* returns seconds since last send/recv */
{
RsStackMutex stack(stunMtx); /********** LOCK MUTEX *********/
#ifdef DEBUG_UDP_STUNNER_FILTER
std::cerr << "UdpStunner::setExclusiveMode();
std::cerr << std::endl;
#endif
if (mExclusiveMode)
{
#ifdef DEBUG_UDP_STUNNER_FILTER
std::cerr << "UdpStunner::setExclusiveMode() FAILED;
std::cerr << std::endl;
#endif
return 0;
}
time_t now = time(NULL);
mExclusiveMode = true;
mExclusiveModeTS = now;
int lastcomms = mStunLastRecvAny;
if (mStunLastSendAny > lastcomms)
{
lastcomms = mStunLastSendAny;
}
int commsage = now - lastcomms;
/* cannot return 0, as this indicates error */
if (commsage == 0)
{
commsage = 1;
}
#ifdef DEBUG_UDP_STUNNER_FILTER
std::cerr << "UdpStunner::setExclusiveMode() SUCCESS. last comms: " << commsage;
std::cerr << " ago";
std::cerr << std::endl;
#endif
return commsage;
}
int UdpStunner::cancelExclusiveMode()
{
RsStackMutex stack(stunMtx); /********** LOCK MUTEX *********/
if (!mExclusiveMode)
{
#ifdef DEBUG_UDP_STUNNER_FILTER
std::cerr << "UdpStunner::cancelExclusiveMode() ERROR, not in exclusive Mode";
std::cerr << std::endl;
#endif
return 0;
}
time_t now = time(NULL);
mExclusiveMode = false;
#ifdef DEBUG_UDP_STUNNER_FILTER
std::cerr << "UdpStunner::cancelExclusiveMode() Canceled. Was in ExclusiveMode for: " << now - mExclusiveModeTS;
std::cerr << " secs";
std::cerr << std::endl;
#endif
return 1;
}
void UdpStunner::setTargetStunPeriod(int32_t sec_per_stun)
{
RsStackMutex stack(stunMtx); /********** LOCK MUTEX *********/
@ -238,12 +311,15 @@ bool UdpStunner::externalAddr(struct sockaddr_in &external, uint8_t &stable)
if (eaddrKnown)
{
/* address timeout */
if (time(NULL) - eaddrTime > (mTargetStunPeriod * 2))
/* address timeout
* no timeout if in exclusive mode
*/
if ((time(NULL) - eaddrTime > (mTargetStunPeriod * 2)) && (!mExclusiveMode))
{
std::cerr << "UdpStunner::externalAddr() eaddr expired";
std::cerr << std::endl;
eaddrKnown = false;
return false;
}
@ -550,14 +626,23 @@ bool UdpStunner::checkStunDesired()
return false; /* all good */
}
if (mExclusiveMode)
{
return false; /* no pings in exclusive mode */
}
if (!eaddrKnown)
{
/* check properly! (this will limit it to two successful stuns) */
if (!locked_checkExternalAddress())
{
#ifdef DEBUG_UDP_STUNNER
std::cerr << "UdpStunner::checkStunDesired() YES, we don't have extAddr Yet";
std::cerr << std::endl;
#endif
return true; /* want our external address */
}
}
/* check if we need to send one now */
now = time(NULL);
@ -567,8 +652,11 @@ bool UdpStunner::checkStunDesired()
* if we have 100% success rate, then we can delay until exactly TARGET RATE.
* if we have 0% success rate, then try at double TARGET RATE.
*
* generalised to a rate_scale parameter below...
*/
double stunPeriod = (mTargetStunPeriod / 2.0) * (1.0 + mSuccessRate);
#define RATE_SCALE (3.0)
double stunPeriod = (mTargetStunPeriod / (RATE_SCALE)) * (1.0 + mSuccessRate * (RATE_SCALE - 1.0));
time_t nextStun = mStunLastRecvResp + (int) stunPeriod;
#ifdef DEBUG_UDP_STUNNER
@ -735,7 +823,10 @@ bool UdpStunner::locked_recvdStun(const struct sockaddr_in &remote, const str
locked_printStunList();
#endif
if (!mExclusiveMode)
{
locked_checkExternalAddress();
}
return found;
}

View File

@ -83,6 +83,10 @@ virtual ~UdpStunner() { return; }
void SetAcceptLocalNet();
#endif
int setExclusiveMode(); /* returns seconds since last send/recv */
int cancelExclusiveMode();
void setTargetStunPeriod(int32_t sec_per_stun);
bool addStunPeer(const struct sockaddr_in &remote, const char *peerid);
bool getStunPeer(int idx, std::string &id,
@ -141,6 +145,8 @@ bool locked_checkExternalAddress();
uint32_t mTargetStunPeriod;
double mSuccessRate;
bool mExclusiveMode; /* when this is switched on, the stunner stays silent (and extAddr is maintained) */
time_t mExclusiveModeTS;
};
/* generic stun functions */