From 00377beb095c246ac00193ce71baef84f531d182 Mon Sep 17 00:00:00 2001 From: Andrew Hanushevsky Date: Thu, 28 Oct 2021 22:27:56 -0700 Subject: [PATCH] [Utils] Add socket utility function. [Utils] Correct interface discovery algorithm for fedora builds. --- src/XrdNet/XrdNetUtils.cc | 61 +++++++++++++++++++++++++++++++++++---- src/XrdNet/XrdNetUtils.hh | 24 +++++++++++++++ 2 files changed, 79 insertions(+), 6 deletions(-) diff --git a/src/XrdNet/XrdNetUtils.cc b/src/XrdNet/XrdNetUtils.cc index 6cd489a8515..0f5eac348b6 100644 --- a/src/XrdNet/XrdNetUtils.cc +++ b/src/XrdNet/XrdNetUtils.cc @@ -356,7 +356,7 @@ const char *XrdNetUtils::GetAddrs(std::vector &hSVec, const char *XrdNetUtils::GetAInfo(XrdNetSpace::hpSpec &aInfo) { - struct addrinfo *xP = 0, *rP = 0, *nP; + struct addrinfo *last4 = 0, *last6 = 0, *xP = 0, *rP = 0, *nP; unsigned short pNum = static_cast(aInfo.port); // Get all of the addresses @@ -367,7 +367,8 @@ const char *XrdNetUtils::GetAInfo(XrdNetSpace::hpSpec &aInfo) return (rc ? gai_strerror(rc) : "host not found"); } -// Count the number of entries we will return and chain the entries +// Count the number of entries we will return and chain the entries. We will +// never return link local addresses which may be returned (shouldn't but does) // do {nP = rP->ai_next; if (rP->ai_family == AF_INET6 || rP->ai_family == AF_INET) @@ -375,17 +376,22 @@ const char *XrdNetUtils::GetAInfo(XrdNetSpace::hpSpec &aInfo) bool v4mapped = false; if (rP->ai_family == AF_INET6) {struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)rP->ai_addr; + if (IN6_IS_ADDR_LINKLOCAL(&ipv6->sin6_addr)) + {rP->ai_next = xP; xP = rP; continue;} v4mapped = IN6_IS_ADDR_V4MAPPED(&ipv6->sin6_addr); } if (aInfo.noOrder || rP->ai_family == AF_INET || v4mapped) - {rP->ai_next = aInfo.aiP4; - aInfo.aiP4 = rP; + {if (last4) last4->ai_next = rP; + else aInfo.aiP4 = rP; + last4 = rP; aInfo.aNum4++; } else { - rP->ai_next = aInfo.aiP6; - aInfo.aiP6 = rP; + if (last6) last6->ai_next = rP; + else aInfo.aiP6 = rP; + last6 = rP; aInfo.aNum6++; } + rP->ai_next = 0; } else {rP->ai_next = xP; xP = rP;} } while((rP = nP)); @@ -482,6 +488,49 @@ const char *XrdNetUtils::GetHostPort(XrdNetSpace::hpSpec &aInfo, return 0; } +/******************************************************************************/ +/* g e t S o k I n f o */ +/******************************************************************************/ + +int XrdNetUtils::GetSokInfo(int fd, char *theAddr, int theALen, char &theType) +{ + XrdNetSockAddr theIP; + XrdNetAddr ipAddr; + static const int fmtopts = XrdNetAddrInfo::noPortRaw + | XrdNetAddrInfo::prefipv4; + SOCKLEN_t addrSize = sizeof(theIP); + int rc; + unsigned short thePort; + +// The the address wanted +// + rc = (fd > 0 ? getpeername( fd, &theIP.Addr, &addrSize) + : getsockname(-fd, &theIP.Addr, &addrSize)); + if (rc) return -errno; + +// Set the address +// + if (ipAddr.Set(&theIP.Addr)) return -EAFNOSUPPORT; + +// Establis the type of address we have +// + if (ipAddr.isIPType(XrdNetAddrInfo::IPv4) || ipAddr.isMapped()) theType='4'; + else theType = '6'; + +// Now format the address +// + if (theAddr && theALen > 0 + && !ipAddr.Format(theAddr, theALen, XrdNetAddrInfo::fmtAddr, fmtopts)) + return -EINVAL; + +// Get the port number and return it. +// + thePort = htons((theIP.Addr.sa_family == AF_INET + ? theIP.v4.sin_port : theIP.v6.sin6_port)); + return static_cast(thePort); +} + + /******************************************************************************/ /* H o s t s */ /******************************************************************************/ diff --git a/src/XrdNet/XrdNetUtils.hh b/src/XrdNet/XrdNetUtils.hh index 1850ed7f2c3..a0b95cc6b90 100644 --- a/src/XrdNet/XrdNetUtils.hh +++ b/src/XrdNet/XrdNetUtils.hh @@ -180,6 +180,30 @@ const char *GetAddrs(std::vector &hSVec, int *ordn=0, AddrOpts opts=allIPMap, unsigned int rotNum=0, bool force=false); +//------------------------------------------------------------------------------ +//! Obtain connection information from a socket. +//! +//! @param fd The file descriptor of the socket whose address is to be +//! converted. The sign of the fd indicates which address: +//! fd > 0 the peer address is used (i.e. getpeername) +//! fd < 0 the local address is used (i.e. getsockname) +//! @param theAddr pointer to a buffer of theAlen bytes where the text +//! version of the IP address is to be returned. The text +//! uses the actual native address format. If theAddr is +//! nil or theAlen is not positive, only the port and +//! address type are returned. +//! @param theALen length of the theAddr buffer. +//! @param theType either the character 4 (IPv4) or 6 (IPv6) is returned. +//! corrresponding to the address family. Note that should +//! be AF_INET6 but the address is mapped, '4' is returned. +//! +//! @return Success: >= 0 corresponding to the port number. +//! @return Failure: < 0 corresponding to -errno. +//------------------------------------------------------------------------------ + +static +int GetSokInfo(int fd, char *theAddr, int theALen, char &theType); + //------------------------------------------------------------------------------ //! Obtain an easily digestable list of hosts. This is the list of up to eight //! unique aliases (i.e. with different addresses) assigned to a base hostname.