Added Code to detect Symmetric NAT (BAD!) Firewalls.

git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@361 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
drbob 2008-02-28 15:58:54 +00:00
parent 6dd3d30d8e
commit 2dc2954f40
14 changed files with 257 additions and 43 deletions

View File

@ -91,6 +91,7 @@ p3ConnectMgr::p3ConnectMgr(p3AuthMgr *am)
{
mUpnpAddrValid = false;
mStunAddrValid = false;
mStunAddrStable = false;
/* setup basics of own state */
if (am)
@ -446,6 +447,7 @@ void p3ConnectMgr::netUdpCheck()
if (stunCheck() || (mUpnpAddrValid))
{
bool extValid = false;
bool extAddrStable = false;
struct sockaddr_in extAddr;
uint32_t mode = 0;
@ -462,21 +464,42 @@ void p3ConnectMgr::netUdpCheck()
{
extValid = true;
extAddr = mUpnpExtAddr;
extAddrStable = true;
}
else if (mStunAddrValid)
{
extValid = true;
extAddr = mStunExtAddr;
extAddrStable = mStunAddrStable;
}
if (extValid)
{
ownState.serveraddr = extAddr;
mode = RS_NET_CONN_TCP_LOCAL | RS_NET_CONN_UDP_DHT_SYNC;
mode = RS_NET_CONN_TCP_LOCAL;
if (mUpnpAddrValid || (ownState.netMode == RS_NET_MODE_EXT))
{
mode |= RS_NET_CONN_TCP_EXTERNAL;
}
else if (extAddrStable)
{
mode |= RS_NET_CONN_UDP_DHT_SYNC;
}
else // if (!extAddrStable)
{
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::netUdpCheck() UDP Unstable :( ";
std::cerr << std::endl;
std::cerr << "p3ConnectMgr::netUdpCheck() We are unreachable";
std::cerr << std::endl;
std::cerr << "netMode => RS_NET_MODE_UNREACHABLE";
std::cerr << std::endl;
#endif
ownState.netMode = RS_NET_MODE_UNREACHABLE;
tou_stunkeepalive(0);
}
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
}
@ -514,24 +537,26 @@ bool p3ConnectMgr::udpExtAddressCheck()
*/
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
uint8_t stable;
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::udpExtAddressCheck()" << std::endl;
#endif
if (0 < tou_extaddr((struct sockaddr *) &addr, &len))
if (0 < tou_extaddr((struct sockaddr *) &addr, &len, &stable))
{
/* update UDP information */
connMtx.lock(); /* LOCK MUTEX */
mStunExtAddr = addr;
mStunAddrValid = true;
mStunAddrStable = (stable != 0);
#ifdef CONN_DEBUG
std::cerr << "p3ConnectMgr::udpExtAddressCheck() Got ";
std::cerr << " addr: " << inet_ntoa(mStunExtAddr.sin_addr);
std::cerr << " port: " << ntohs(mStunExtAddr.sin_port);
std::cerr << ":" << ntohs(mStunExtAddr.sin_port);
std::cerr << " stable: " << mStunAddrStable;
std::cerr << std::endl;
#endif
@ -1217,10 +1242,15 @@ void p3ConnectMgr::peerStatus(std::string id,
{
it->second.netMode = RS_NET_MODE_EXT;
}
else
else if (flags & RS_NET_FLAGS_STABLE_UDP)
{
it->second.netMode = RS_NET_MODE_UDP;
}
else
{
it->second.netMode = RS_NET_MODE_UNREACHABLE;
}
/* always update VIS status */
if (flags & RS_NET_FLAGS_USE_DISC)
@ -1243,6 +1273,39 @@ void p3ConnectMgr::peerStatus(std::string id,
IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/
}
/* Determine Reachability (only advisory) */
if (ownState.netMode == RS_NET_MODE_UDP)
{
if ((details.type & RS_NET_CONN_UDP_DHT_SYNC) ||
(details.type & RS_NET_CONN_TCP_EXTERNAL))
{
/* reachable! */
it->second.state &= (~RS_PEER_S_UNREACHABLE);
}
else
{
/* unreachable */
it->second.state |= RS_PEER_S_UNREACHABLE;
}
}
else if (ownState.netMode == RS_NET_MODE_UNREACHABLE)
{
if (details.type & RS_NET_CONN_TCP_EXTERNAL)
{
/* reachable! */
it->second.state &= (~RS_PEER_S_UNREACHABLE);
}
else
{
/* unreachable */
it->second.state |= RS_PEER_S_UNREACHABLE;
}
}
else
{
it->second.state &= (~RS_PEER_S_UNREACHABLE);
}
if (!isFriend)
{
std::cerr << "p3ConnectMgr::peerStatus() NOT FRIEND ";
@ -1896,7 +1959,7 @@ bool p3ConnectMgr::retryConnect(std::string id)
}
#endif
if (it->second.netMode != RS_NET_MODE_EXT)
if (it->second.netMode == RS_NET_MODE_UDP)
{
std::cerr << "p3ConnectMgr::retryConnect() trying UDP connection!";
std::cerr << " id: " << id;
@ -1907,7 +1970,7 @@ bool p3ConnectMgr::retryConnect(std::string id)
}
else
{
std::cerr << "p3ConnectMgr::retryConnect() EXT so not trying UDP connection!";
std::cerr << "p3ConnectMgr::retryConnect() EXT/UNREACHABLE so not trying UDP connection!";
std::cerr << " id: " << id;
std::cerr << std::endl;
}

View File

@ -63,13 +63,13 @@ const uint32_t RS_NET_MODE_TRY_UPNP = 0x0020;
const uint32_t RS_NET_MODE_TRY_UDP = 0x0040;
/* Actual State */
const uint32_t RS_NET_MODE_ACTUAL = 0x000f;
const uint32_t RS_NET_MODE_ACTUAL = 0x000f;
const uint32_t RS_NET_MODE_UNKNOWN = 0x0000;
const uint32_t RS_NET_MODE_EXT = 0x0001;
const uint32_t RS_NET_MODE_UPNP = 0x0002;
const uint32_t RS_NET_MODE_UDP = 0x0004;
const uint32_t RS_NET_MODE_ERROR = 0x0008;
const uint32_t RS_NET_MODE_UNKNOWN = 0x0000;
const uint32_t RS_NET_MODE_EXT = 0x0001;
const uint32_t RS_NET_MODE_UPNP = 0x0002;
const uint32_t RS_NET_MODE_UDP = 0x0004;
const uint32_t RS_NET_MODE_UNREACHABLE = 0x0008;
/* order of attempts ... */
@ -86,6 +86,7 @@ const uint32_t RS_NET_FLAGS_USE_DISC = 0x0001;
const uint32_t RS_NET_FLAGS_USE_DHT = 0x0002;
const uint32_t RS_NET_FLAGS_ONLINE = 0x0004;
const uint32_t RS_NET_FLAGS_EXTERNAL_ADDR = 0x0008;
const uint32_t RS_NET_FLAGS_STABLE_UDP = 0x0010;
class peerAddrInfo
{
@ -287,6 +288,7 @@ private:
/* external Address determination */
bool mUpnpAddrValid, mStunAddrValid;
bool mStunAddrStable;
struct sockaddr_in mUpnpExtAddr;
struct sockaddr_in mStunExtAddr;

View File

@ -36,8 +36,6 @@
* #define P3DHTMGR_USE_LOCAL_UDP_CONN 1 // For Testing only
****/
#define P3DHTMGR_USE_LOCAL_UDP_CONN 1 // For Testing only
/**** DHT State Variables ****
* TODO:
* (1) notify call in.
@ -57,8 +55,8 @@
/* TIMEOUTS */
#define DHT_SEARCH_PERIOD 1800 /* PeerKeys: if we haven't found them: 30 min */
#define DHT_CHECK_PERIOD 3600 /* PeerKeys: re-lookup peer: 60 min */
#define DHT_PUBLISH_PERIOD 1800 /* OwnKey 30 min */
#define DHT_CHECK_PERIOD 1800 /* PeerKeys: re-lookup peer: 30 min */
#define DHT_PUBLISH_PERIOD 900 /* OwnKey 30 min (15 minutes for now) */
#define DHT_NOTIFY_PERIOD 300 /* 5 min - Notify Check period */
#define DHT_RESTART_PERIOD 300 /* 5 min */
@ -547,8 +545,9 @@ int p3DhtMgr::checkOwnDHTKeys()
/* check for connect requests */
if ((peer.state == DHT_PEER_PUBLISHED) &&
(!(peer.type & RS_NET_CONN_TCP_EXTERNAL)))
//if ((peer.state == DHT_PEER_PUBLISHED) &&
// (!(peer.type & RS_NET_CONN_TCP_EXTERNAL)))
if (peer.state == DHT_PEER_PUBLISHED)
{
if (now - peer.notifyTS >= DHT_NOTIFY_PERIOD)
{

View File

@ -46,6 +46,7 @@ const uint32_t RS_PEER_ACTION_MASK = 0xff00;
const uint32_t RS_PEER_S_FRIEND = 0x0001;
const uint32_t RS_PEER_S_ONLINE = 0x0002; /* heard from recently..*/
const uint32_t RS_PEER_S_CONNECTED = 0x0004;
const uint32_t RS_PEER_S_UNREACHABLE = 0x0008;
/* ACTIONS */
const uint32_t RS_PEER_NEW = 0x0001; /* new Peer */

View File

@ -44,6 +44,7 @@ const uint32_t RS_TRUST_LVL_GOOD = 0x0003;
const uint32_t RS_NETMODE_UDP = 0x0001;
const uint32_t RS_NETMODE_UPNP = 0x0002;
const uint32_t RS_NETMODE_EXT = 0x0003;
const uint32_t RS_NETMODE_UNREACHABLE = 0x0004;
/* Visibility */
const uint32_t RS_VS_DHT_ON = 0x0001;
@ -53,6 +54,7 @@ const uint32_t RS_VS_DISC_ON = 0x0002;
const uint32_t RS_PEER_STATE_FRIEND = 0x0001;
const uint32_t RS_PEER_STATE_ONLINE = 0x0002;
const uint32_t RS_PEER_STATE_CONNECTED = 0x0004;
const uint32_t RS_PEER_STATE_UNREACHABLE= 0x0008;
/* A couple of helper functions for translating the numbers games */

View File

@ -62,6 +62,10 @@ std::string RsPeerStateString(uint32_t state)
{
str = "Connected";
}
else if (state & RS_PEER_STATE_UNREACHABLE)
{
str = "Unreachable";
}
else if (state & RS_PEER_STATE_ONLINE)
{
str = "Available";
@ -92,6 +96,10 @@ std::string RsPeerNetModeString(uint32_t netModel)
{
str = "UDP Mode";
}
else if (netModel == RS_NETMODE_UNREACHABLE)
{
str = "UDP Mode (Unreachable)";
}
else
{
str = "Unknown NetMode";
@ -272,6 +280,8 @@ bool p3Peers::getPeerDetails(std::string id, RsPeerDetails &d)
d.state |= RS_PEER_STATE_ONLINE;
if (pcs.state & RS_PEER_S_CONNECTED)
d.state |= RS_PEER_STATE_CONNECTED;
if (pcs.state & RS_PEER_S_UNREACHABLE)
d.state |= RS_PEER_STATE_UNREACHABLE;
switch(pcs.netMode & RS_NET_MODE_ACTUAL)
{
@ -282,11 +292,13 @@ bool p3Peers::getPeerDetails(std::string id, RsPeerDetails &d)
d.netMode = RS_NETMODE_UPNP;
break;
case RS_NET_MODE_UDP:
case RS_NET_MODE_UNKNOWN:
case RS_NET_MODE_ERROR:
default:
d.netMode = RS_NETMODE_UDP;
break;
case RS_NET_MODE_UNREACHABLE:
case RS_NET_MODE_UNKNOWN:
default:
d.netMode = RS_NETMODE_UNREACHABLE;
break;
}
if (pcs.netMode & RS_NET_MODE_TRY_EXT)
@ -433,6 +445,9 @@ bool p3Peers::setNetworkMode(std::string id, uint32_t extNetMode)
case RS_NETMODE_UDP:
netMode = RS_NET_MODE_UDP;
break;
case RS_NETMODE_UNREACHABLE:
netMode = RS_NET_MODE_UNREACHABLE;
break;
default:
break;
}

View File

@ -54,8 +54,9 @@ static int convertTRangeToTDelta(int trange);
const uint32_t P3DISC_FLAGS_USE_DISC = 0x0001;
const uint32_t P3DISC_FLAGS_USE_DHT = 0x0002;
const uint32_t P3DISC_FLAGS_EXTERNAL_ADDR = 0x0004;
const uint32_t P3DISC_FLAGS_PEER_ONLINE = 0x0008;
const uint32_t P3DISC_FLAGS_OWN_DETAILS = 0x0010;
const uint32_t P3DISC_FLAGS_STABLE_UDP = 0x0008;
const uint32_t P3DISC_FLAGS_PEER_ONLINE = 0x0010;
const uint32_t P3DISC_FLAGS_OWN_DETAILS = 0x0020;
#define P3DISC_DEBUG 1
@ -342,6 +343,11 @@ void p3disc::sendOwnDetails(std::string to)
{
di->discFlags |= P3DISC_FLAGS_EXTERNAL_ADDR;
}
else if (detail.netMode & RS_NET_MODE_UDP)
{
di->discFlags |= P3DISC_FLAGS_STABLE_UDP;
}
di->discFlags |= P3DISC_FLAGS_OWN_DETAILS;
/* send msg */
@ -415,6 +421,10 @@ void p3disc::sendPeerDetails(std::string to, std::string about)
{
di->discFlags |= P3DISC_FLAGS_EXTERNAL_ADDR;
}
else if (detail.netMode & RS_NET_MODE_UDP)
{
di->discFlags |= P3DISC_FLAGS_STABLE_UDP;
}
if (detail.state & RS_PEER_S_CONNECTED)
{
@ -484,6 +494,12 @@ void p3disc::recvPeerOwnMsg(RsDiscItem *item)
flags |= RS_NET_FLAGS_EXTERNAL_ADDR;
}
if (item->discFlags & P3DISC_FLAGS_STABLE_UDP)
{
type |= RS_NET_CONN_UDP_DHT_SYNC;
flags |= RS_NET_FLAGS_STABLE_UDP;
}
mConnMgr->peerStatus(item->PeerId(), item->laddr, item->saddr,
type, flags, RS_CB_PERSON);
@ -546,6 +562,12 @@ void p3disc::recvPeerFriendMsg(RsDiscReply *item)
flags |= RS_NET_FLAGS_EXTERNAL_ADDR;
}
if (item->discFlags & P3DISC_FLAGS_STABLE_UDP)
{
type |= RS_NET_CONN_UDP_DHT_SYNC;
flags |= RS_NET_FLAGS_STABLE_UDP;
}
/* only valid certs, and not ourselves */
if ((loaded) && (peerId != mConnMgr->getOwnId()))
{

View File

@ -107,12 +107,12 @@ int tou_tick_stunkeepalive()
return 1;
}
int tou_extaddr(struct sockaddr *ext_addr, socklen_t *addrlen)
int tou_extaddr(struct sockaddr *ext_addr, socklen_t *addrlen, uint8_t *stable)
{
if (!tou_inited)
return -1;
if (udps->externalAddr(*(struct sockaddr_in *) ext_addr))
if (udps->externalAddr(*(struct sockaddr_in *) ext_addr, *stable))
{
return 1;
}

View File

@ -72,7 +72,7 @@ extern "C" {
*/
int tou_init(const struct sockaddr *my_addr, socklen_t addrlen);
int tou_extaddr(struct sockaddr *ext_addr, socklen_t *addrlen);
int tou_extaddr(struct sockaddr *ext_addr, socklen_t *addrlen, uint8_t *stable);
int tou_stunpeer(const struct sockaddr *ext_addr, socklen_t addrlen, const char *id);
int tou_stunkeepalive(int required);
int tou_tick_stunkeepalive();

View File

@ -39,7 +39,7 @@ static const int STUN_TTL = 64;
#define DEBUG_UDP_SORTER 1
UdpSorter::UdpSorter(struct sockaddr_in &local)
:udpLayer(NULL), laddr(local), eaddrKnown(false),
:udpLayer(NULL), laddr(local), eaddrKnown(false), eaddrStable(false),
mStunKeepAlive(false), mStunLastRecv(0), mStunLastSend(0)
@ -234,10 +234,7 @@ bool UdpSorter::locked_handleStunPkt(void *data, int size, struct sockaddr_in &f
std::cerr << inet_ntoa(eAddr.sin_addr) << ":" << ntohs(eAddr.sin_port);
std::cerr << std::endl;
#endif
eaddrKnown = true;
eaddr = eAddr;
locked_recvdStun(from);
locked_recvdStun(from, eAddr);
return true;
}
@ -251,11 +248,17 @@ bool UdpSorter::locked_handleStunPkt(void *data, int size, struct sockaddr_in &f
}
bool UdpSorter::externalAddr(struct sockaddr_in &external)
bool UdpSorter::externalAddr(struct sockaddr_in &external, uint8_t &stable)
{
if (eaddrKnown)
{
external = eaddr;
if (eaddrStable)
stable = 1;
else
stable = 0;
return true;
}
return false;
@ -612,15 +615,21 @@ bool UdpSorter::checkStunKeepAlive()
}
bool UdpSorter::locked_recvdStun(const struct sockaddr_in &remote)
bool UdpSorter::locked_recvdStun(const struct sockaddr_in &remote, const struct sockaddr_in &extaddr)
{
#ifdef DEBUG_UDP_SORTER
std::cerr << "UdpSorter::recvdStun()";
std::cerr << std::endl;
std::ostringstream out;
out << "UdpSorter::locked_recvdStun() from:";
out << inet_ntoa(remote.sin_addr) << ":" << ntohs(remote.sin_port);
out << " claiming ExtAddr is:";
out << inet_ntoa(extaddr.sin_addr) << ":" << ntohs(extaddr.sin_port);
std::cerr << out.str() << std::endl;
#endif
locked_printStunList();
bool found = true;
std::list<TouStunPeer>::iterator it;
for(it = mStunList.begin(); it != mStunList.end(); it++)
{
@ -628,13 +637,85 @@ bool UdpSorter::locked_recvdStun(const struct sockaddr_in &remote)
(remote.sin_port == it->remote.sin_port))
{
it->failCount = 0;
return true;
it->eaddr = extaddr;
it->response = true;
found = true;
break;
}
}
if (!eaddrKnown)
{
locked_checkExternalAddress();
}
return found;
}
bool UdpSorter::locked_checkExternalAddress()
{
#ifdef DEBUG_UDP_SORTER
std::ostringstream out;
out << "UdpSorter::locked_checkExternalAddress()";
std::cerr << out.str() << std::endl;
#endif
bool found1 = false;
bool found2 = false;
std::list<TouStunPeer>::iterator it;
std::list<TouStunPeer>::iterator p1;
std::list<TouStunPeer>::iterator p2;
for(it = mStunList.begin(); it != mStunList.end(); it++)
{
if (it->response)
{
if (!found1)
{
p1 = it;
found1 = true;
}
else
{
p2 = it;
found2 = true;
break;
}
}
}
if (found1 && found2)
{
if ((p1->eaddr.sin_addr.s_addr == p2->eaddr.sin_addr.s_addr) &&
(p1->eaddr.sin_port == p2->eaddr.sin_port))
{
eaddrStable = true;
}
else
{
eaddrStable = false;
}
eaddrKnown = true;
eaddr = p1->eaddr;
#ifdef DEBUG_UDP_SORTER
std::cerr << "UdpSorter::locked_checkExternalAddress() Found State:";
if (eaddrStable)
std::cerr << " Stable NAT translation (GOOD!) ";
else
std::cerr << " unStable (symmetric NAT translation (BAD!) ";
std::cerr << std::endl;
#endif
return true;
}
return false;
}
bool UdpSorter::locked_printStunList()
{
std::ostringstream out;

View File

@ -49,13 +49,14 @@ class TouStunPeer
{
public:
TouStunPeer()
:lastsend(0), failCount(0) { return; }
:response(false), lastsend(0), failCount(0) { return; }
TouStunPeer(std::string id_in, const struct sockaddr_in &addr)
:id(id_in), remote(addr), lastsend(0), failCount(0) { return; }
:id(id_in), remote(addr), response(false), lastsend(0), failCount(0) { return; }
std::string id;
struct sockaddr_in remote;
struct sockaddr_in remote, eaddr;
bool response;
time_t lastsend;
uint32_t failCount;
};
@ -75,7 +76,7 @@ bool setStunKeepAlive(uint32_t required);
bool addStunPeer(const struct sockaddr_in &remote, const char *peerid);
bool checkStunKeepAlive();
bool externalAddr(struct sockaddr_in &remote);
bool externalAddr(struct sockaddr_in &remote, uint8_t &stable);
/* Packet IO */
/* pass-through send packets */
@ -108,7 +109,9 @@ bool generate_stun_pkt(void *stun_pkt, int *len);
/* stun keepAlive */
bool locked_printStunList();
bool locked_recvdStun(const struct sockaddr_in &remote);
bool locked_recvdStun(const struct sockaddr_in &remote, const struct sockaddr_in &extaddr);
bool locked_checkExternalAddress();
bool storeStunPeer(const struct sockaddr_in &remote, const char *peerid);
UdpLayer *udpLayer;
@ -116,8 +119,10 @@ bool storeStunPeer(const struct sockaddr_in &remote, const char *peerid);
RsMutex sortMtx; /* for all class data (below) */
struct sockaddr_in laddr; /* local addr */
struct sockaddr_in eaddr; /* external addr */
bool eaddrKnown;
bool eaddrStable; /* if true then usable. if false -> Symmettric NAT */
bool mStunKeepAlive;
time_t mStunLastRecv;

View File

@ -251,6 +251,15 @@ void PeersDialog::insertPeers()
item -> setIcon(0,(QIcon(IMAGE_ONLINE)));
}
}
else if (detail.state & RS_PEER_STATE_UNREACHABLE)
{
/* bright green */
for(i = 1; i < 12; i++)
{
item -> setBackground(i,QBrush(Qt::red));
item -> setIcon(0,(QIcon(IMAGE_OFFLINE)));
}
}
else if (detail.state & RS_PEER_STATE_ONLINE)
{
/* bright green */

View File

@ -144,10 +144,13 @@ void ServerDialog::load()
case RS_NETMODE_UDP:
out << "Firewalled";
break;
default:
case RS_NETMODE_UPNP:
out << "Automatic: UPnP Forwarded Port";
break;
default:
case RS_NETMODE_UNREACHABLE:
out << "Unreachable: Firewalled by Symmetric NAT";
break;
}
out << std::endl;
out << "\tLocal Address: " << detail.localAddr;
@ -175,6 +178,16 @@ void ServerDialog::load()
out << std::endl;
if (detail.netMode == RS_NETMODE_UNREACHABLE)
{
ui.netStatusBox->setTextColor( Qt::red );
}
else
{
ui.netStatusBox->setTextColor( Qt::black );
}
ui.netStatusBox->setText(QString::fromStdString(out.str()));
ui.netStatusBox ->setReadOnly(true);

View File

@ -44,6 +44,7 @@ const uint32_t RS_TRUST_LVL_GOOD = 0x0003;
const uint32_t RS_NETMODE_UDP = 0x0001;
const uint32_t RS_NETMODE_UPNP = 0x0002;
const uint32_t RS_NETMODE_EXT = 0x0003;
const uint32_t RS_NETMODE_UNREACHABLE = 0x0004;
/* Visibility */
const uint32_t RS_VS_DHT_ON = 0x0001;
@ -53,6 +54,7 @@ const uint32_t RS_VS_DISC_ON = 0x0002;
const uint32_t RS_PEER_STATE_FRIEND = 0x0001;
const uint32_t RS_PEER_STATE_ONLINE = 0x0002;
const uint32_t RS_PEER_STATE_CONNECTED = 0x0004;
const uint32_t RS_PEER_STATE_UNREACHABLE= 0x0008;
/* A couple of helper functions for translating the numbers games */