Improve parsing of IPv6 addresses

Implement the following rules:
* Interpret [X]:Y as host=X port=Y, if Y is an integer
* Interpret X:Y as host=X port=Y, if Y is an integer and X contains no colon
* Interpret X:Y as host=X:Y port=default otherwise
This commit is contained in:
Pieter Wuille 2012-05-30 22:44:23 +02:00
parent d59bce21e5
commit 1e8aeae15a
2 changed files with 27 additions and 43 deletions

View file

@ -33,6 +33,27 @@ enum Network ParseNetwork(std::string net) {
return NET_UNROUTABLE; return NET_UNROUTABLE;
} }
void SplitHostPort(std::string in, int &portOut, std::string &hostOut) {
size_t colon = in.find_last_of(':');
// if a : is found, and it either follows a [...], or no other : is in the string, treat it as port separator
bool fHaveColon = colon != in.npos;
bool fBracketed = fHaveColon && (in[0]=='[' && in[colon-1]==']'); // if there is a colon, and in[0]=='[', colon is not 0, so in[colon-1] is safe
bool fMultiColon = fHaveColon && (in.find_last_of(':',colon-1) != in.npos);
if (fHaveColon && (colon==0 || fBracketed || !fMultiColon)) {
char *endp = NULL;
int n = strtol(in.c_str() + colon + 1, &endp, 10);
if (endp && *endp == 0 && n >= 0) {
in = in.substr(0, colon);
if (n > 0 && n < 0x10000)
portOut = n;
}
}
if (in.size()>0 && in[0] == '[' && in[in.size()-1] == ']')
hostOut = in.substr(1, in.size()-2);
else
hostOut = in;
}
bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup) bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup)
{ {
vIP.clear(); vIP.clear();
@ -114,36 +135,11 @@ bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault,
if (pszName[0] == 0) if (pszName[0] == 0)
return false; return false;
int port = portDefault; int port = portDefault;
char psz[256]; std::string hostname = "";
char *pszHost = psz; SplitHostPort(std::string(pszName), port, hostname);
strlcpy(psz, pszName, sizeof(psz));
char* pszColon = strrchr(psz+1,':');
char *pszPortEnd = NULL;
int portParsed = pszColon ? strtoul(pszColon+1, &pszPortEnd, 10) : 0;
if (pszColon && pszPortEnd && pszPortEnd[0] == 0)
{
if (psz[0] == '[' && pszColon[-1] == ']')
{
pszHost = psz+1;
pszColon[-1] = 0;
}
else
pszColon[0] = 0;
if (port >= 0 && port <= USHRT_MAX)
port = portParsed;
}
else
{
if (psz[0] == '[' && psz[strlen(psz)-1] == ']')
{
pszHost = psz+1;
psz[strlen(psz)-1] = 0;
}
}
std::vector<CNetAddr> vIP; std::vector<CNetAddr> vIP;
bool fRet = LookupIntern(pszHost, vIP, nMaxSolutions, fAllowLookup); bool fRet = LookupIntern(hostname.c_str(), vIP, nMaxSolutions, fAllowLookup);
if (!fRet) if (!fRet)
return false; return false;
vAddr.resize(vIP.size()); vAddr.resize(vIP.size());
@ -496,22 +492,9 @@ bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout)
bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault, int nTimeout) bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault, int nTimeout)
{ {
string strDest(pszDest); string strDest;
int port = portDefault; int port = portDefault;
SplitHostPort(string(pszDest), port, strDest);
// split hostname and port
size_t colon = strDest.find_last_of(':');
if (colon != strDest.npos) {
char *endp = NULL;
int n = strtol(pszDest + colon + 1, &endp, 10);
if (endp && *endp == 0 && n >= 0) {
strDest = strDest.substr(0, colon);
if (n > 0 && n < 0x10000)
port = n;
}
}
if (strDest[0] == '[' && strDest[strDest.size()-1] == ']')
strDest = strDest.substr(1, strDest.size()-2);
SOCKET hSocket = INVALID_SOCKET; SOCKET hSocket = INVALID_SOCKET;
CService addrResolved(CNetAddr(strDest, fNameLookup && !nameproxyInfo.second), port); CService addrResolved(CNetAddr(strDest, fNameLookup && !nameproxyInfo.second), port);

View file

@ -133,6 +133,7 @@ class CService : public CNetAddr
}; };
enum Network ParseNetwork(std::string net); enum Network ParseNetwork(std::string net);
void SplitHostPort(std::string in, int &portOut, std::string &hostOut);
bool SetProxy(enum Network net, CService addrProxy, int nSocksVersion = 5); bool SetProxy(enum Network net, CService addrProxy, int nSocksVersion = 5);
bool GetProxy(enum Network net, CService &addrProxy); bool GetProxy(enum Network net, CService &addrProxy);
bool IsProxy(const CNetAddr &addr); bool IsProxy(const CNetAddr &addr);