XRootD
Loading...
Searching...
No Matches
XrdNetAddrInfo.cc File Reference
#include <cctype>
#include <cerrno>
#include <netdb.h>
#include <cstdio>
#include <arpa/inet.h>
#include <sys/types.h>
#include "XrdNet/XrdNetAddrInfo.hh"
#include "XrdNet/XrdNetCache.hh"
+ Include dependency graph for XrdNetAddrInfo.cc:

Go to the source code of this file.

Macros

#define IN6_IS_ADDR_UNIQLOCAL(a)    ( ((const uint8_t *)(a))[0] == 0xfc || ((const uint8_t *)(a))[0] == 0xfd )
 
#define IS_INET(x)   (x == AF_INET || x == AF_INET6)
 
#define MY_FAMILY   IP.Addr.sa_family
 
#define UR_FAMILY   ipAddr->IP.Addr.sa_family
 

Macro Definition Documentation

◆ IN6_IS_ADDR_UNIQLOCAL

#define IN6_IS_ADDR_UNIQLOCAL (   a)     ( ((const uint8_t *)(a))[0] == 0xfc || ((const uint8_t *)(a))[0] == 0xfd )

Definition at line 63 of file XrdNetAddrInfo.cc.

72{
73 static const char lbVal[13] ={0,0,0,0,0,0,0,0,0,0,0,0,0x7f};
74};
75
76/******************************************************************************/
77/* F o r m a t */
78/******************************************************************************/
79
80int XrdNetAddrInfo::Format(char *bAddr, int bLen, fmtUse theFmt, int fmtOpts)
81{
82 const char *pFmt = "]:%d";
83 int totLen, n, pNum, addBrak = 0;
84 int omitP = (fmtOpts & (noPort|noPortRaw));
85 int ipRaw = (fmtOpts & noPortRaw);
86 int ipOld = fmtOpts & (old6Map4 | prefipv4);
87
88// Handle the degenerative case first
89//
90 if (IP.Addr.sa_family == AF_UNIX)
91 {n = (omitP ? snprintf(bAddr, bLen, "localhost")
92 : snprintf(bAddr, bLen, "localhost:%s", unixPipe->sun_path));
93 return (n < bLen ? n : QFill(bAddr, bLen));
94 }
95
96// Grab the potr. The port number is the same position and same size regardless
97// of address type.
98//
99 pNum = ntohs(IP.v4.sin_port);
100
101// Resolve address if need be and return result if possible
102//
103 if (theFmt == fmtName || theFmt == fmtAuto)
104 {if (!hostName && dnsCache && !(hostName = dnsCache->Find(this))
105 && theFmt == fmtName) Resolve();
106 if (hostName)
107 {n = (omitP ? snprintf(bAddr, bLen, "%s", hostName)
108 : snprintf(bAddr, bLen, "%s:%d", hostName, pNum));
109 return (n < bLen ? n : QFill(bAddr, bLen));
110 }
111 theFmt = fmtAddr;
112 }
113
114// Check if we can now produce an address format quickly. We used assume that
115// the hostname was an address if it started with a non-alpha. But this does
116// not correspond to RFC 1178 and RFC 3696, among others. We now only use
117// the optimization path if the name is actually an IPV6/mapped4 address.
118//
119 if (hostName && *hostName == '[' && !ipOld)
120 {n = (omitP ? snprintf(bAddr, bLen, "%s", hostName)
121 : snprintf(bAddr, bLen, "%s:%d", hostName, pNum));
122 return (n < bLen ? n : QFill(bAddr, bLen));
123 }
124
125// Format address
126//
127 if (IP.Addr.sa_family == AF_INET6)
128 {if (bLen < (INET6_ADDRSTRLEN+2)) return QFill(bAddr, bLen);
129 if (ipOld && IN6_IS_ADDR_V4MAPPED(&IP.v6.sin6_addr))
130 { if (fmtOpts & prefipv4) {n = 0; pFmt = ":%d";}
131 else if (ipRaw) {strcpy(bAddr, "::"); n = 2;}
132 else {strcpy(bAddr, "[::"); n = 3; addBrak=1;}
133 if (!inet_ntop(AF_INET, &IP.v6.sin6_addr.s6_addr32[3],
134 bAddr+n, bLen-n)) return QFill(bAddr, bLen);
135 } else {
136 if (!ipRaw) {*bAddr = '['; n = 1; addBrak = 1;}
137 else n = 0;
138 if (!inet_ntop(AF_INET6,&(IP.v6.sin6_addr),bAddr+n,bLen-n))
139 return QFill(bAddr, bLen);
140 }
141 }
142 else if (IP.Addr.sa_family == AF_INET)
143 {if (theFmt != fmtAdv6) {n = 0; pFmt = ":%d";}
144 else {if (bLen < (INET_ADDRSTRLEN+9)) return QFill(bAddr, bLen);
145 if (fmtOpts & old6Map4) {strcpy(bAddr, "[::"); n = 3;}
146 else {strcpy(bAddr, "[::ffff:"); n = 8;}
147 if (ipRaw) {strcpy(bAddr, bAddr+1); n--;}
148 addBrak = 1;
149 }
150 if (!inet_ntop(AF_INET, &(IP.v4.sin_addr),bAddr+n,bLen-n))
151 return QFill(bAddr, bLen);
152 }
153 else return QFill(bAddr, bLen);
154
155// Recalculate buffer position and length
156//
157 totLen = strlen(bAddr); bAddr += totLen; bLen -= totLen;
158
159// Process when no port number wanted
160//
161 if (omitP)
162 {if (addBrak)
163 {if (bLen < 2) return QFill(bAddr, bLen);
164 *bAddr++ = ']'; *bAddr = 0; totLen++;
165 }
166 return totLen;
167 }
168
169// Add the port number and return result
170//
171 if ((n = snprintf(bAddr, bLen, pFmt, pNum)) >= bLen)
172 return QFill(bAddr, bLen);
173 return totLen+n;
174}
175
176/******************************************************************************/
177/* i s L o o p b a c k */
178/******************************************************************************/
179
181{
182
183// Check for loopback address
184//
185 if (IP.Addr.sa_family == AF_INET)
186 return !memcmp(&IP.v4.sin_addr.s_addr, &lbVal[12], 1);
187
188 if (IP.Addr.sa_family == AF_INET6)
189 return !memcmp(&IP.v6.sin6_addr, &in6addr_loopback, sizeof(in6_addr))
190 || !memcmp(&IP.v6.sin6_addr, lbVal, sizeof(lbVal));
191
192 return false;
193}
194
195/******************************************************************************/
196/* i s P r i v a t e */
197/******************************************************************************/
198
200{
201 unsigned char *ipV4 = 0;
202
203// For IPV6 addresses we will use the macro unless it is mapped
204//
205 if (IP.Addr.sa_family == AF_INET6)
206 {if ((IN6_IS_ADDR_V4MAPPED(&IP.v6.sin6_addr)))
207 ipV4 = (unsigned char *)&IP.v6.sin6_addr.s6_addr32[3];
208 else {if ((IN6_IS_ADDR_LINKLOCAL(&IP.v6.sin6_addr))
209 || (IN6_IS_ADDR_SITELOCAL(&IP.v6.sin6_addr))
210 || (IN6_IS_ADDR_UNIQLOCAL(&IP.v6.sin6_addr))
211 || (IN6_IS_ADDR_LOOPBACK (&IP.v6.sin6_addr))) return true;
212 return false;
213 }
214 }
215
216// If this is not an IPV4 address then we will consider it private
217//
218 if (!ipV4)
219 {if (IP.Addr.sa_family != AF_INET) return true;
220 ipV4 = (unsigned char *)&IP.v4.sin_addr.s_addr;
221 }
222
223// For IPV4 we use the RFC definition of private. Note that this includes
224// mapped addresses which, as odd as it is, we could get.
225//
226 if (ipV4[0] == 10
227 || (ipV4[0] == 172 && ipV4[1] >= 16 && ipV4[1] <= 31)
228 || (ipV4[0] == 192 && ipV4[1] == 168)
229 || (ipV4[0] == 169 && ipV4[1] == 254)
230 || ipV4[0] == 127) return true;
231
232// Not a local address
233//
234 return false;
235}
236
237/******************************************************************************/
238/* i s R e g i s t e r e d */
239/******************************************************************************/
240
242{
243 const char *hName;
244
245// Simply see if we can resolve this name
246//
247 if (!(hName = Name())) return false;
248 return isHostName(hName);
249}
250
251/******************************************************************************/
252/* i s U s i n g T L S */
253/******************************************************************************/
254
256{
257 return (protFlgs & isTLS) != 0;
258}
259
260/******************************************************************************/
261/* Private: L o w C a s e */
262/******************************************************************************/
263
264char *XrdNetAddrInfo::LowCase(char *str)
265{
266 unsigned char *sp = (unsigned char*)str;
267
268 while(*sp) {if (isupper((int)*sp)) *sp = (char)tolower((int)*sp); sp++;}
269
270 return str;
271}
272
273/******************************************************************************/
274/* i s H o s t N a m e */
275/******************************************************************************/
276
277bool XrdNetAddrInfo::isHostName(const char *name)
278{
279 const char *dot;
280 int dnum;
281
282// First check for Iv6 format or hostname
283//
284 if (*name == '[') return false;
285 if (!isdigit(*name)) return true;
286
287// The IPv4 case is more complicated. The fastest way here is this is a
288// host name if there are no dots or if the last component is not a digit
289// according to the RFC spec.
290//
291 if (!(dot = rindex(name, '.')) || !isdigit(*(dot+1))) return true;
292
293// We are not out of the woods yet. Now we need to do a full check.
294//
295 name++; dnum = 0;
296 while(*name)
297 {if (*name == '.') dnum++;
298 else if (!isdigit(*name)) return true;
299 name++;
300 }
301 return (dnum == 3 ? false : true);
302}
303
304/******************************************************************************/
305/* N a m e */
306/******************************************************************************/
307
308const char *XrdNetAddrInfo::Name(const char *eName, const char **eText)
309{
310 int rc;
311
312// Preset errtxt to zero
313//
314 if (eText) *eText = 0;
315
316// Check for unix family which is equal to localhost.
317//
318 if (IP.Addr.sa_family == AF_UNIX) return "localhost";
319
320// If we already translated this name, just return the translation
321//
322 if (hostName || (dnsCache && (hostName = dnsCache->Find(this))))
323 return hostName;
324
325// Try to resolve this address
326//
327 if (!(rc = Resolve())) return hostName;
328
329// We failed resolving this address
330//
331 if (eText) *eText = gai_strerror(rc);
332 return eName;
333}
334
335/******************************************************************************/
336/* P o r t */
337/******************************************************************************/
338
340{
341// Make sure we have a proper address family here
342//
343 if (IP.Addr.sa_family != AF_INET && IP.Addr.sa_family != AF_INET6)
344 return -1;
345
346// Return port number
347//
348 return ntohs(IP.v6.sin6_port);
349}
350
351/******************************************************************************/
352/* Private: Q F i l l */
353/******************************************************************************/
354
355int XrdNetAddrInfo::QFill(char *bAddr, int bLen)
356{
357 static const char quests[] = "????????";
358
359// Insert up to 8 question marks
360//
361 if (bLen)
362 {strncpy(bAddr, quests, bLen);
363 bAddr[bLen-1] = 0;
364 }
365 return 0;
366}
367
368/******************************************************************************/
369/* Private: R e s o l v e */
370/******************************************************************************/
371
373{
374 char hBuff[NI_MAXHOST];
375 int n, rc;
376
377// Free up hostname here
378//
379 if (hostName) {free(hostName); hostName = 0;}
380
381// Determine the actual size of the address structure
382//
383 if (IP.Addr.sa_family == AF_INET ) n = sizeof(IP.v4);
384 else if (IP.Addr.sa_family == AF_INET6) n = sizeof(IP.v6);
385 else if (IP.Addr.sa_family == AF_UNIX )
386 {hostName = strdup("localhost");
387 return 0;
388 }
389 else return EAI_FAMILY;
390
391// Do lookup of canonical name. If an error is returned we simply assume that
392// the name is not resolvable and return the address as the host name.
393//
394 if ((rc = getnameinfo(&IP.Addr, n, hBuff+1, sizeof(hBuff)-2, 0, 0, 0)))
395 {int ec = errno;
396 if (Format(hBuff, sizeof(hBuff), fmtAddr, noPort))
397 {hostName = strdup(hBuff); return 0;}
398 errno = ec;
399 return rc;
400 }
401
402// Handle the case when the mapping returned an actual name or an address
403// We always want numeric ipv6 addresses surrounded by brackets. Additionally,
404// some implementations of getnameinfo() return the scopeid when a numeric
405// address is returned. We check and remove it.
406//
407 if (!index(hBuff+1, ':')) hostName = strdup(LowCase(hBuff+1));
408 else {char *perCent = index(hBuff+1, '%');
409 if (perCent) *perCent = 0;
410 n = strlen(hBuff+1);
411 hBuff[0] = '['; hBuff[n+1] = ']'; hBuff[n+2] = 0;
412 hostName = strdup(hBuff);
413 }
414
415// Add the entry to the cache and return success
416//
417 if (dnsCache) dnsCache->Add(this, hostName);
418 return 0;
419}
420
421/******************************************************************************/
422/* S a m e */
423/******************************************************************************/
424
425#define IS_INET(x) (x == AF_INET || x == AF_INET6)
426
427#define MY_FAMILY IP.Addr.sa_family
428
429#define UR_FAMILY ipAddr->IP.Addr.sa_family
430
431int XrdNetAddrInfo::Same(const XrdNetAddrInfo *ipAddr, bool plusPort)
432{
433 static const int ipv4ASZ = sizeof(IP.v4.sin_addr);
434
435 bool isINet = IS_INET(MY_FAMILY) && IS_INET(UR_FAMILY);
436
437// Do port comparison if requested and makes sense to do it
438//
439 if (plusPort && isINet)
440 {in_port_t port1, port2;
441 port1 = (MY_FAMILY == AF_INET ? IP.v4.sin_port : IP.v6.sin6_port);
442 port2 = (UR_FAMILY == AF_INET ? ipAddr->IP.v4.sin_port
443 : ipAddr->IP.v6.sin6_port);
444 if (port1 != port2) return 0;
445 }
446
447// If address families do not match, they are the same if the hostnames match.
448// If we don't have a hostname and the addresses are convertable, we can
449// compare the actual addresses.
450//
451 if (MY_FAMILY != UR_FAMILY)
452 {if (!isINet) return 0;
453 if (hostName && ipAddr->hostName)
454 return !strcmp(hostName,ipAddr->hostName);
455 if (MY_FAMILY == AF_INET && ipAddr->isMapped())
456 return !memcmp(&IP.v4.sin_addr,
457 &(ipAddr->IP.v6.sin6_addr.s6_addr32[3]), ipv4ASZ);
458 if (isMapped() && UR_FAMILY == AF_INET)
459 return !memcmp(&IP.v6.sin6_addr.s6_addr32[3],
460 &(ipAddr->IP.v4.sin_addr), ipv4ASZ);
461 return 0;
462 }
463
464// Now process to do the match
465//
466 if (MY_FAMILY == AF_INET)
467 return !memcmp(&IP.v4.sin_addr, &(ipAddr->IP.v4.sin_addr), ipv4ASZ);
468 else if (MY_FAMILY == AF_INET6)
469 return !memcmp(&IP.v6.sin6_addr, &(ipAddr->IP.v6.sin6_addr),
470 sizeof(IP.v6.sin6_addr));
471 else if (MY_FAMILY == AF_UNIX)
472 return !strcmp(unixPipe->sun_path, ipAddr->unixPipe->sun_path);
473
474 return 0;
475}
#define UR_FAMILY
#define IS_INET(x)
#define MY_FAMILY
#define IN6_IS_ADDR_UNIQLOCAL(a)
struct sockaddr_in6 v6
struct sockaddr Addr
struct sockaddr_in v4
static XrdNetCache * dnsCache
static const int noPort
Do not add port number.
static const int old6Map4
Use deprecated IPV6 mapped format.
bool isMapped() const
static bool isHostName(const char *name)
unsigned char protFlgs
XrdNetSockAddr IP
static const int noPortRaw
Use raw address format (no port)
int Same(const XrdNetAddrInfo *ipAddr, bool plusPort=false)
static const int prefipv4
Use if mapped IPV4 actual format.
int Format(char *bAddr, int bLen, fmtUse fmtType=fmtAuto, int fmtOpts=0)
char * LowCase(char *str)
int QFill(char *bAddr, int bLen)
@ fmtAddr
Address using suitable ipv4 or ipv6 format.
@ fmtName
Hostname if it is resolvable o/w use fmtAddr.
@ fmtAuto
Hostname if already resolved o/w use fmtAddr.
static const char isTLS
Location using TLS.
const char * Name(const char *eName=0, const char **eText=0)
void Add(XrdNetAddrInfo *hAddr, const char *hName)
char * Find(XrdNetAddrInfo *hAddr)

◆ IS_INET

#define IS_INET (   x)    (x == AF_INET || x == AF_INET6)

Definition at line 426 of file XrdNetAddrInfo.cc.

◆ MY_FAMILY

#define MY_FAMILY   IP.Addr.sa_family

Definition at line 428 of file XrdNetAddrInfo.cc.

◆ UR_FAMILY

#define UR_FAMILY   ipAddr->IP.Addr.sa_family

Definition at line 430 of file XrdNetAddrInfo.cc.