diff --git a/libretroshare/src/dht/connectstatebox.cc b/libretroshare/src/dht/connectstatebox.cc index 6ae7e63a1..1d01884e9 100644 --- a/libretroshare/src/dht/connectstatebox.cc +++ b/libretroshare/src/dht/connectstatebox.cc @@ -30,6 +30,7 @@ #include #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; @@ -82,6 +87,10 @@ std::string StateAsString(uint32_t state) case CSB_START: str = "Start"; break; + + case CSB_TCP_WAIT: + str = "TCP Wait"; + break; case CSB_DIRECT_ATTEMPT: str = "Direct Attempt"; @@ -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); @@ -302,7 +316,7 @@ uint32_t PeerConnectStateBox::connectCb_direct() case CSB_FAILED_WAIT: { /* if too soon */ - if (now - mStateTS < FAILED_WAIT_TIME) + if (now - mStateTS < FAILED_WAIT_TIME) { /* same state */ retval = CSB_ACTION_WAIT; @@ -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,23 +463,42 @@ uint32_t PeerConnectStateBox::connectCb_unreachable() } /* FALLTHROUGH TO START CASE */ case CSB_START: { - /* starting up the connection */ - if (mState != CSB_NETSTATE_FIREWALLED) + 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) { - stateMsg(std::cerr, "not Firewalled => PROXY_ATTEMPT", 0); - mState = CSB_PROXY_ATTEMPT; - retval = CSB_ACTION_PROXY_CONN | proxyPortMode; + /* same state */ + retval = CSB_ACTION_WAIT; } else { - stateMsg(std::cerr, "Firewalled => RELAY_ATTEMPT", 0); - mState = CSB_RELAY_ATTEMPT; - retval = CSB_ACTION_RELAY_CONN | CSB_ACTION_DHT_PORT; - } + /* starting up the connection */ + if (mState != CSB_NETSTATE_FIREWALLED) + { + stateMsg(std::cerr, "not Firewalled => PROXY_ATTEMPT", 0); + mState = CSB_PROXY_ATTEMPT; + retval = CSB_ACTION_PROXY_CONN | proxyPortMode; + } + else + { + stateMsg(std::cerr, "Firewalled => RELAY_ATTEMPT", 0); + mState = CSB_RELAY_ATTEMPT; + retval = CSB_ACTION_RELAY_CONN | CSB_ACTION_DHT_PORT; - mStateTS = now; - mNoAttempts = 0; + } + + mStateTS = now; + mNoAttempts = 0; + } } break; diff --git a/libretroshare/src/dht/connectstatebox.h b/libretroshare/src/dht/connectstatebox.h index ef1ee7992..ec53ad495 100644 --- a/libretroshare/src/dht/connectstatebox.h +++ b/libretroshare/src/dht/connectstatebox.h @@ -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 diff --git a/libretroshare/src/pqi/p3netmgr.cc b/libretroshare/src/pqi/p3netmgr.cc index 6ba62dcc3..c72411e53 100644 --- a/libretroshare/src/pqi/p3netmgr.cc +++ b/libretroshare/src/pqi/p3netmgr.cc @@ -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() { diff --git a/libretroshare/src/pqi/pqinetstatebox.cc b/libretroshare/src/pqi/pqinetstatebox.cc index 2c7ef5e0a..721d631f8 100644 --- a/libretroshare/src/pqi/pqinetstatebox.cc +++ b/libretroshare/src/pqi/pqinetstatebox.cc @@ -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; diff --git a/libretroshare/src/pqi/pqinetstatebox.h b/libretroshare/src/pqi/pqinetstatebox.h index 4a6333c72..128b7283b 100644 --- a/libretroshare/src/pqi/pqinetstatebox.h +++ b/libretroshare/src/pqi/pqinetstatebox.h @@ -66,6 +66,7 @@ class pqiNetStateBox bool mStunProxySet; time_t mStunProxyTS; bool mStunProxyStable; + bool mStunProxySemiStable; struct sockaddr_in mStunProxyAddr; bool mDhtSet; diff --git a/libretroshare/src/retroshare/rsconfig.h b/libretroshare/src/retroshare/rsconfig.h index 88d622f72..b86d61f14 100644 --- a/libretroshare/src/retroshare/rsconfig.h +++ b/libretroshare/src/retroshare/rsconfig.h @@ -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 diff --git a/libretroshare/src/tcponudp/udpstunner.cc b/libretroshare/src/tcponudp/udpstunner.cc index e77eabb62..603a7ccc2 100644 --- a/libretroshare/src/tcponudp/udpstunner.cc +++ b/libretroshare/src/tcponudp/udpstunner.cc @@ -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,13 +626,22 @@ 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; + std::cerr << "UdpStunner::checkStunDesired() YES, we don't have extAddr Yet"; + std::cerr << std::endl; #endif - return true; /* want our external address */ + return true; /* want our external address */ + } } /* check if we need to send one now */ @@ -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 - locked_checkExternalAddress(); + if (!mExclusiveMode) + { + locked_checkExternalAddress(); + } return found; } diff --git a/libretroshare/src/tcponudp/udpstunner.h b/libretroshare/src/tcponudp/udpstunner.h index 99fe98459..e720402e5 100644 --- a/libretroshare/src/tcponudp/udpstunner.h +++ b/libretroshare/src/tcponudp/udpstunner.h @@ -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 */