From 2b15e49192657ba838e94c9530725665e44ff24b Mon Sep 17 00:00:00 2001 From: Andrew Hanushevsky Date: Fri, 20 Dec 2019 00:27:53 -0800 Subject: [PATCH] [Server] Proide fallback when an IPv6 address is missing a ptr record. --- src/Xrd/XrdLink.cc | 9 ++++ src/Xrd/XrdLink.hh | 12 ++++++ src/Xrd/XrdLinkXeq.cc | 19 +++++++++ src/Xrd/XrdLinkXeq.hh | 2 + src/XrdCms/XrdCmsClientMan.cc | 12 +++++- src/XrdCms/XrdCmsConfig.cc | 7 +++- src/XrdCms/XrdCmsProtocol.cc | 78 ++++++++++++++++++++++++++++++++++- src/XrdNet/XrdNetAddr.cc | 36 ++++++++++++++++ src/XrdNet/XrdNetAddr.hh | 13 ++++++ 9 files changed, 184 insertions(+), 4 deletions(-) diff --git a/src/Xrd/XrdLink.cc b/src/Xrd/XrdLink.cc index fd455b1e31d..71ef7bb06d8 100644 --- a/src/Xrd/XrdLink.cc +++ b/src/Xrd/XrdLink.cc @@ -285,6 +285,15 @@ int XrdLink::RecvAll(char *Buff, int Blen, int timeout) return linkXQ.RecvAll (Buff, Blen, timeout); } +/******************************************************************************/ +/* R e g i s t e r */ +/******************************************************************************/ + +bool XrdLink::Register(const char *hName) +{ + return linkXQ.Register(hName); +} + /******************************************************************************/ /* S e n d */ /******************************************************************************/ diff --git a/src/Xrd/XrdLink.hh b/src/Xrd/XrdLink.hh index 6c113957ec0..387c5462815 100644 --- a/src/Xrd/XrdLink.hh +++ b/src/Xrd/XrdLink.hh @@ -326,6 +326,18 @@ int Recv(char *buff, int blen, int timeout); int RecvAll(char *buff, int blen, int timeout=-1); +//------------------------------------------------------------------------------ +//! Register a host name with this IP address. This is not MT-safe! +//! +//! @param hName -> to a true host name which should be fully qualified. +//! One of the IP addresses registered to this name must +//! match the IP address associated with this object. +//! +//! @return True: Specified name is now associated with this link. +//! False: Nothing changed, registration could not be verified. +//------------------------------------------------------------------------------ + +bool Register(const char *hName); //----------------------------------------------------------------------------- //! Send data on a link. This calls may block unless the socket was marked //! nonblocking. If a block would occur, the data is copied for later sending. diff --git a/src/Xrd/XrdLinkXeq.cc b/src/Xrd/XrdLinkXeq.cc index ee6d0c128c1..1b58bac3a4d 100644 --- a/src/Xrd/XrdLinkXeq.cc +++ b/src/Xrd/XrdLinkXeq.cc @@ -454,6 +454,25 @@ int XrdLinkXeq::RecvAll(char *Buff, int Blen, int timeout) return -1; } +/******************************************************************************/ +/* R e g i s t e r */ +/******************************************************************************/ + +bool XrdLinkXeq::Register(const char *hName) +{ + +// First see if we can register this name with the address object +// + if (!Addr.Register(hName)) return false; + +// Make appropriate changes here +// + if (HostName) free(HostName); + HostName = strdup(hName); + strlcpy(Lname, hName, sizeof(Lname)); + return true; +} + /******************************************************************************/ /* S e n d */ /******************************************************************************/ diff --git a/src/Xrd/XrdLinkXeq.hh b/src/Xrd/XrdLinkXeq.hh index 798803db760..0761b875b02 100644 --- a/src/Xrd/XrdLinkXeq.hh +++ b/src/Xrd/XrdLinkXeq.hh @@ -91,6 +91,8 @@ int Recv(char *buff, int blen, int timeout); int RecvAll(char *buff, int blen, int timeout=-1); +bool Register(const char *hName); + int Send(const char *buff, int blen); int Send(const struct iovec *iov, int iocnt, int bytes=0); diff --git a/src/XrdCms/XrdCmsClientMan.cc b/src/XrdCms/XrdCmsClientMan.cc index 0ee2c8725f2..b8ae8d2fd70 100644 --- a/src/XrdCms/XrdCmsClientMan.cc +++ b/src/XrdCms/XrdCmsClientMan.cc @@ -323,7 +323,8 @@ int XrdCmsClientMan::Hookup() EPNAME("Hookup"); CmsLoginData Data; XrdLink *lp; - char buff[256]; + char buff[256], hnBuff[264]; + kXR_char *envData = 0; int rc, oldWait, tries = 12, opts = 0; // Turn off our debugging and version flags @@ -332,6 +333,14 @@ int XrdCmsClientMan::Hookup() doDebug &= ~manMask; manMutex.UnLock(); +// Report our hostname (there are better ways of doing this) +// + const char *hn = getenv("XRDHOST"); + if (hn) + {snprintf(hnBuff, sizeof(hnBuff), "myHN=%s", hn); + envData = (kXR_char *)hnBuff; + } + // Keep trying to connect to the manager. Note that we bind the link to this // thread to make sure we get notified should another thread close the socket. // @@ -343,6 +352,7 @@ int XrdCmsClientMan::Hookup() } // lp->Bind(XrdSysThread::ID()); memset(&Data, 0, sizeof(Data)); + Data.envCGI = envData; Data.Mode = CmsLoginData::kYR_director; Data.HoldTime = static_cast(getpid()); if (!(rc = XrdCmsLogin::Login(lp, Data))) break; diff --git a/src/XrdCms/XrdCmsConfig.cc b/src/XrdCms/XrdCmsConfig.cc index 13983960bf7..d0a3800b256 100644 --- a/src/XrdCms/XrdCmsConfig.cc +++ b/src/XrdCms/XrdCmsConfig.cc @@ -369,6 +369,11 @@ int XrdCmsConfig::Configure2() char *p, buff[512]; std::string envData; +// Add our host name to the env +// + envData += "myHN="; + envData += myName; + // Print herald // sprintf(buff, " phase 2 %s initialization started.", myRole); @@ -414,7 +419,7 @@ int XrdCmsConfig::Configure2() else {if (QTRACE(Debug)) Say.Say("Config ", "Global System Identification: ", mySID); if (Config.mySite) - {envData += "site="; + {envData += "&site="; envData += mySite; } } diff --git a/src/XrdCms/XrdCmsProtocol.cc b/src/XrdCms/XrdCmsProtocol.cc index c03303d41a9..00f1a478015 100644 --- a/src/XrdCms/XrdCmsProtocol.cc +++ b/src/XrdCms/XrdCmsProtocol.cc @@ -365,6 +365,23 @@ void XrdCmsProtocol::Pander(const char *manager, int mport) } Netopts = 0; tries = waits = 6; + // Verify that this node has the real DNS name if it's IPv6 + // + if (!(Link->AddrInfo()->isRegistered()) + && Link->AddrInfo()->isIPType(XrdNetAddrInfo::IPv6)) + {char *oldName = strdup(Link->Host()); + Say.Emsg("Protocol", oldName, "is missing an IPv6 ptr record; " + "attempting local registration as", manp); + if (!(Link->Register(manp))) + {Say.Emsg("Protocol", oldName, + "registration failed; address mismatch."); + } else { + Say.Emsg("Protocol", oldName, + "is now locally registered as", manp); + } + free(oldName); + } + // Obtain a new node object for this connection // if (!(myNode = Manager->Add(Link, Lvl+1, terminate))) @@ -557,7 +574,30 @@ int XrdCmsProtocol::Stats(char *buff, int blen, int do_sync) /******************************************************************************/ /* A d m i t */ /******************************************************************************/ - + +namespace +{ +char *getAltName(char *sid, char *buff, int blen) +{ + char *atsign, *spacec, *retval = 0; + int n; + if (sid) + if ((atsign = index(sid, '@'))) + {atsign++; + if ((spacec = index(atsign, ' '))) + {*spacec = 0; + n = strlen(atsign); + if (n > 3 && n < blen) + {strcpy(buff, atsign); + retval = buff; + } + *spacec = ' '; + } + } + return retval; +} +} + XrdCmsRouting *XrdCmsProtocol::Admit() { EPNAME("Admit"); @@ -590,6 +630,41 @@ XrdCmsRouting *XrdCmsProtocol::Admit() // if (!Source.Admit(Link, Data, Config.mySID, envP)) return 0; +// Construct environment for incomming node +// + XrdOucEnv cgiEnv((const char *)Data.envCGI); + +// We have this problem hat many times the IPv6 address is missing the ptr +// record in DNS. If this node is IPv6 unregistered and the incomming node +// supplied it's host name then we can attempt to register it locally. +// + if (!(Link->AddrInfo()->isRegistered()) + && Link->AddrInfo()->isIPType(XrdNetAddrInfo::IPv6)) + {const char *altName = cgiEnv.Get("myHN"); + const char *altType = "stated mapping"; + char hBF[256], *oldName = strdup(Link->Host()); + if (!altName) {altName = getAltName((char *)Data.SID, hBF, sizeof(hBF)); + altType = "inferred mapping"; + } + Say.Emsg("Protocol", "DNS lookup for", oldName, "failed; " + "IPv6 ptr record missing!"); + if (!altName) + {Say.Emsg("Protocol", oldName, "did not supply a fallback " + "mapping; using IPv6 address."); + } else { + char buff[512]; + snprintf(buff, sizeof(buff), "%s -> %s", oldName, altName); + Say.Emsg("Protocol", "Attempting to use", altType, buff); + if (!(Link->Register(altName))) + {Say.Emsg("Protocol", buff, altType,"failed; address mismatch."); + } else { + Say.Emsg("Protocol", oldName, + "is now locally registered as", altName); + } + } + free(oldName); + } + // Handle Redirectors here (minimal stuff to do) // if (Data.Mode & CmsLoginData::kYR_director) @@ -736,7 +811,6 @@ XrdCmsRouting *XrdCmsProtocol::Admit() // Document the login // - XrdOucEnv cgiEnv((const char *)Data.envCGI); const char *sname = cgiEnv.Get("site"); const char *lfmt = (myNode->isMan > 1 ? "Standby%s%s" : "Primary%s%s"); snprintf(envBuff,sizeof(envBuff),lfmt,(sname ? " ":""),(sname ? sname : "")); diff --git a/src/XrdNet/XrdNetAddr.cc b/src/XrdNet/XrdNetAddr.cc index 147b3209f90..b03c7bc8cb7 100644 --- a/src/XrdNet/XrdNetAddr.cc +++ b/src/XrdNet/XrdNetAddr.cc @@ -164,6 +164,42 @@ int XrdNetAddr::Port(int pNum) return pNum; } +/******************************************************************************/ +/* R e g i s t e r */ +/******************************************************************************/ + +bool XrdNetAddr::Register(const char *hName) +{ + XrdNetAddr *aListVec = 0; + int i, aListNum; + +// Step one is to make sure the incomming name is not an address +// + if (!isHostName(hName)) return false; + +// The next step is to get all of the IP addresses registered for this name +// + if (XrdNetUtils::GetAddrs(hName, &aListVec, aListNum, + XrdNetUtils::allIPMap, XrdNetUtils::NoPortRaw)) + return false; + +// In order to use the given name, one of the IP addresses in the list must +// match our address. This is about as secure we can get. +// + for (i = 0; i < aListNum; i++) {if (Same(&aListVec[i])) break;} + delete [] aListVec; + +// If we didn't find a match, report it +// + if (i >= aListNum) return false; + +// Replace current hostname with the wanted one +// + if (hostName) free(hostName); + hostName = strdup(hName); + return true; +} + /******************************************************************************/ /* S e t */ /******************************************************************************/ diff --git a/src/XrdNet/XrdNetAddr.hh b/src/XrdNet/XrdNetAddr.hh index 0647c54d598..8b0dd81ddb3 100644 --- a/src/XrdNet/XrdNetAddr.hh +++ b/src/XrdNet/XrdNetAddr.hh @@ -72,6 +72,19 @@ static bool IPV4Set() {return useIPV4;} int Port(int pNum=-1); +//------------------------------------------------------------------------------ +//! Register a host name with this IP address. This is not MT-safe! +//! +//! @param hName -> to a true host name which should be fully qualified. +//! One of the IP addresses registered to this name must +//! match the IP address associated with this object. +//! +//! @return True: Specified name is now associated with this address. +//! False: Nothing changed, registration could not be verified. +//------------------------------------------------------------------------------ + +bool Register(const char *hName); + //------------------------------------------------------------------------------ //! Set the IP address and possibly the port number. //!