XRootD
XrdNetUtils.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d N e t U t i l s . c c */
4 /* */
5 /* (c) 2013 by the Board of Trustees of the Leland Stanford, Jr., University */
6 /* All Rights Reserved */
7 /* Produced by Andrew Hanushevsky for Stanford University under contract */
8 /* DE-AC02-76-SFO0515 with the Department of Energy */
9 /* */
10 /* This file is part of the XRootD software suite. */
11 /* */
12 /* XRootD is free software: you can redistribute it and/or modify it under */
13 /* the terms of the GNU Lesser General Public License as published by the */
14 /* Free Software Foundation, either version 3 of the License, or (at your */
15 /* option) any later version. */
16 /* */
17 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
18 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
19 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
20 /* License for more details. */
21 /* */
22 /* You should have received a copy of the GNU Lesser General Public License */
23 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
24 /* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
25 /* */
26 /* The copyright holder's institutional names and contributor's names may not */
27 /* be used to endorse or promote products derived from this software without */
28 /* specific prior written permission of the institution or contributor. */
29 /******************************************************************************/
30 
31 #include <cctype>
32 #include <cinttypes>
33 #include <netdb.h>
34 #include <cstring>
35 #include <unistd.h>
36 
37 #include <netinet/in.h>
38 #include <sys/socket.h>
39 #include <sys/types.h>
40 #include <fcntl.h>
41 #include <poll.h>
42 
43 #include "XrdNet/XrdNetAddr.hh"
44 #include "XrdNet/XrdNetIdentity.hh"
45 #include "XrdNet/XrdNetIF.hh"
46 #include "XrdNet/XrdNetRegistry.hh"
47 #include "XrdNet/XrdNetUtils.hh"
48 #include "XrdOuc/XrdOucTList.hh"
49 #include "XrdOuc/XrdOucUtils.hh"
50 #include "XrdSys/XrdSysE2T.hh"
51 #include "XrdSys/XrdSysPlatform.hh"
52 #ifndef HAVE_PROTOR
53 #include "XrdSys/XrdSysPthread.hh"
54 #endif
55 
56 /******************************************************************************/
57 /* S t a t i c M e m b e r s */
58 /******************************************************************************/
59 
60 int XrdNetUtils::autoFamily;
61 
62 // The following also sets autoFamily!
63 //
64 int XrdNetUtils::autoHints = XrdNetUtils::SetAuto(XrdNetUtils::prefAuto);
65 
66 /******************************************************************************/
67 /* D e c o d e */
68 /******************************************************************************/
69 
70 int XrdNetUtils::Decode(XrdNetSockAddr *sadr, const char *buff, int blen)
71 {
72  static const int ipv4Sz = sizeof(struct in_addr)*2+4;
73  static const int ipv6Sz = sizeof(struct in6_addr)*2+4;
74  char bval[sizeof(struct in6_addr)+2];
75  int isv6, n, i = 0, Odd = 0;
76 
77 // Determine if this will be IPV4 or IPV6 (only ones allowed)
78 //
79  if (blen == ipv6Sz) isv6 = 1;
80  else if (blen == ipv4Sz) isv6 = 0;
81  else return -1;
82 
83 // Convert the whole string to a temporary
84 //
85  while(blen--)
86  { if (*buff >= '0' && *buff <= '9') n = *buff-48;
87  else if (*buff >= 'a' && *buff <= 'f') n = *buff-87;
88  else if (*buff >= 'A' && *buff <= 'F') n = *buff-55;
89  else return -1;
90  if (Odd) bval[i++] |= n;
91  else bval[i ] = n << 4;
92  buff++; Odd = ~Odd;
93  }
94 
95 // Clear the address
96 //
97  memset(sadr, 0, sizeof(XrdNetSockAddr));
98 
99 // Copy out the data, as needed
100 //
101  if (isv6)
102  {sadr->v6.sin6_family = AF_INET6;
103  memcpy(&(sadr->v6.sin6_port), bval, 2);
104  memcpy(&(sadr->v6.sin6_addr), &bval[2], sizeof(struct in6_addr));
105  } else {
106  sadr->v4.sin_family = AF_INET;
107  memcpy(&(sadr->v4.sin_port), bval, 2);
108  memcpy(&(sadr->v4.sin_addr), &bval[2], sizeof(struct in_addr));
109  }
110 
111 // Return the converted port (it's the same for v4/v6)
112 //
113  return static_cast<int>(ntohs(sadr->v6.sin6_port));
114 }
115 
116 /******************************************************************************/
117 /* E n c o d e */
118 /******************************************************************************/
119 
120 int XrdNetUtils::Encode(const XrdNetSockAddr *sadr, char *buff, int blen,
121  int port)
122 {
123  static const char *hv = "0123456789abcdef";
124  char *src, bval[sizeof(struct in6_addr)+2];
125  int asz, i, j = 0;
126 
127 // Compute the size we need for the buffer (note we only support IP4/6)
128 //
129  if (sadr->Addr.sa_family == AF_INET6)
130  {src = (char *)&(sadr->v6.sin6_addr); asz = sizeof(struct in6_addr);}
131  else if (sadr->Addr.sa_family == AF_INET)
132  {src = (char *)&(sadr->v4.sin_addr); asz = sizeof(struct in_addr); }
133  else return 0;
134  if (blen < (asz*2)+5) return -((asz*2)+5);
135 
136 // Get the port value in the first two bytes followed by the address.
137 //
138  if (port < 0) memcpy(bval, &(sadr->v6.sin6_port), 2);
139  else {short sPort = htons(static_cast<short>(port));
140  memcpy(bval, &sPort, 2);
141  }
142  memcpy(&bval[2], src, asz);
143  asz += 2;
144 
145 // Now convert to hex
146 //
147  for (i = 0; i < asz; i++)
148  {buff[j++] = hv[(bval[i] >> 4) & 0x0f];
149  buff[j++] = hv[ bval[i] & 0x0f];
150  }
151  buff[j] = '\0';
152 
153 // All done
154 //
155  return asz*2;
156 }
157 
158 /******************************************************************************/
159 /* Private: F i l l A d d r s */
160 /******************************************************************************/
161 
162 #define OrderXX (XrdNetUtils::order46 | XrdNetUtils::order64)
163 
164 #define SIN_PORT(x) ((struct sockaddr_in *)(x->ai_addr))->sin_port
165 namespace XrdNetSpace
166 {
167 struct hpSpec
168  {const char *ipAddr;
169  addrinfo hints;
170  addrinfo *aiP4;
171  int aNum4;
172  int aNum6;
173  addrinfo *aiP6;
174  int port;
175  bool map426;
176  bool noOrder;
177  bool order46;
178  bool onlyUDP;
179  char ipMap[7]; // ::ffff: (length = 7)
180  char ipAdr[MAXHOSTNAMELEN+15];
181 
183  : aiP4(0), aNum4(0), aNum6(0), aiP6(0), map426(false),
184  noOrder((opts & OrderXX) == 0),
185  order46((opts & XrdNetUtils::order46) != 0),
186  onlyUDP((opts & XrdNetUtils::onlyUDP) != 0) {}
187 
188  ~hpSpec() {if (aiP4) freeaddrinfo(aiP4);
189  if (aiP6) freeaddrinfo(aiP6);
190  }
191  };
192 }
193 using namespace XrdNetSpace;
194 
195 void XrdNetUtils::FillAddr(XrdNetSpace::hpSpec &aInfo, XrdNetAddr *aVec,
196  int *ordn, unsigned int rotNum)
197 {
198  struct addrinfo *aP, *nP[2];
199  int aN[2];
200 
201 // Establish ordering
202 //
203  if (aInfo.order46)
204  {nP[0] = aInfo.aiP4; aN[0] = aInfo.aNum4;
205  nP[1] = aInfo.aiP6; aN[1] = aInfo.aNum6;
206  } else {
207  nP[0] = aInfo.aiP6; aN[0] = aInfo.aNum6;
208  nP[1] = aInfo.aiP4; aN[1] = aInfo.aNum4;
209  }
210 
211  for (int k = 0; k < 2; k++)
212  {int sz = aN[k];
213  if (sz && (aP = nP[k]))
214  {int iBeg = rotNum % sz, iEnd = sz;
215  do {for (int i = iBeg; i < iEnd && aP; i++)
216  {int pNum = int(SIN_PORT(aP)) & 0x0000ffff;
217  aVec[i].Set(aP, pNum, aInfo.map426);
218  aP = aP->ai_next;
219  }
220  iEnd = iBeg; iBeg = 0;
221  } while(aP);
222  aVec = &aVec[sz];
223  }
224  }
225 
226 // Supply the ordinal if it is wanted
227 //
228  if (ordn)
229  {if (aInfo.noOrder) *ordn = aInfo.aNum4 + aInfo.aNum6;
230  else if (aInfo.order46) *ordn = aInfo.aNum4;
231  else *ordn = aInfo.aNum6;
232  }
233 }
234 
235 /******************************************************************************/
236 /* G e t A d d r s */
237 /******************************************************************************/
238 
239 const char *XrdNetUtils::GetAddrs(const char *hSpec,
240  XrdNetAddr *aVec[], int &aVsz,
241  XrdNetUtils::AddrOpts opts, int pNum)
242 {
243  const char *eText;
244  hpSpec aInfo(opts);
245 
246 // Prep the returned fields
247 //
248  *aVec = 0;
249  aVsz = 0;
250 
251 // Parse the options
252 //
253  GetHints(aInfo, opts);
254 
255 // Parse the host specification and get addresses
256 //
257  if ((eText = GetHostPort(aInfo, hSpec, pNum))
258  || (eText = GetAInfo(aInfo))) return eText;
259 
260 // If we have any addresses, resize the vector with that many netaddr objects
261 // and then initialze each one of them.
262 //
263  if (aInfo.aNum4 || aInfo.aNum6)
264  {aVsz = aInfo.aNum4 + aInfo.aNum6;
265  *aVec = new XrdNetAddr[(unsigned int)aVsz];
266  FillAddr(aInfo, *aVec);
267  }
268 
269 // All done
270 //
271  return 0;
272 }
273 
274 /******************************************************************************/
275 
276 const char *XrdNetUtils::GetAddrs(const std::string &hSpec,
277  std::vector<XrdNetAddr> &aVec,
278  int *ordn, AddrOpts opts, int pNum)
279 {
280 // If this references a registered name, process it as such.
281 //
282  if (*(hSpec.c_str()) == XrdNetRegistry::pfx)
283  return XrdNetRegistry::GetAddrs(hSpec, aVec, ordn, opts, pNum);
284 
285 // Start up!
286 //
287  const char *eText;
288  hpSpec aInfo(opts);
289 
290 // Clear the result vector
291 //
292  aVec.clear();
293  if (ordn) *ordn = 0;
294 
295 // Parse the options
296 //
297  GetHints(aInfo, opts);
298 
299 // Parse the host specification and get address info
300 //
301  if ((eText = GetHostPort(aInfo, hSpec.c_str(), pNum))
302  || (eText = GetAInfo(aInfo))) return eText;
303 
304 // If we have any addresses, resize the vector with that many netaddr objects
305 // and then initialze each one of them.
306 //
307  if (aInfo.aNum4 || aInfo.aNum6)
308  {aVec.resize(aInfo.aNum4 + aInfo.aNum6);
309  FillAddr(aInfo, aVec.data(), ordn);
310  }
311 
312 // All done
313 //
314  return 0;
315 }
316 
317 /******************************************************************************/
318 
319 const char *XrdNetUtils::GetAddrs(std::vector<std::string> &hSVec,
320  std::vector<XrdNetAddr> &aVec, int *ordn,
321  AddrOpts opts, unsigned int rotNum,
322  bool force)
323 {
324  const char *eText;
325  hpSpec aInfo(opts);
326 
327 // Clear the result vector and make sure we have something to do
328 //
329  aVec.clear();
330  if (ordn) *ordn = 0;
331  if (!hSVec.size()) return 0;
332 
333 // Parse the options
334 //
335  GetHints(aInfo, opts);
336 
337 // Process each specification
338 //
339  for (int i = 0; i < (int)hSVec.size(); i++)
340  {if (((eText = GetHostPort(aInfo, hSVec[i].c_str(), PortInSpec))
341  || (eText = GetAInfo(aInfo))) && !force) return eText;
342  }
343 
344 // Size the vector and fill it in
345 //
346  if (aInfo.aNum4 || aInfo.aNum6)
347  {aVec.resize(aInfo.aNum4 + aInfo.aNum6);
348  FillAddr(aInfo, aVec.data(), ordn, rotNum);
349  }
350 
351 // All done
352 //
353  return 0;
354 }
355 
356 /******************************************************************************/
357 /* Private: G e t A I n f o */
358 /******************************************************************************/
359 
360 const char *XrdNetUtils::GetAInfo(XrdNetSpace::hpSpec &aInfo)
361 {
362  struct addrinfo *last4 = 0, *last6 = 0, *xP = 0, *rP = 0, *nP;
363  unsigned short pNum = static_cast<unsigned short>(aInfo.port);
364 
365 // Get all of the addresses
366 //
367  int rc = getaddrinfo(aInfo.ipAddr, 0, &aInfo.hints, &rP);
368  if (rc || !rP)
369  {if (rP) freeaddrinfo(rP);
370  return (rc ? gai_strerror(rc) : "host not found");
371  }
372 
373 // Count the number of entries we will return and chain the entries. We will
374 // never return link local addresses which may be returned (shouldn't but does)
375 //
376  do {nP = rP->ai_next;
377  if (rP->ai_family == AF_INET6 || rP->ai_family == AF_INET)
378  {SIN_PORT(rP) = pNum;
379  bool v4mapped = false;
380  if (rP->ai_family == AF_INET6)
381  {struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)rP->ai_addr;
382  if (IN6_IS_ADDR_LINKLOCAL(&ipv6->sin6_addr))
383  {rP->ai_next = xP; xP = rP; continue;}
384  v4mapped = IN6_IS_ADDR_V4MAPPED(&ipv6->sin6_addr);
385  }
386  if (aInfo.noOrder || rP->ai_family == AF_INET || v4mapped)
387  {if (last4) last4->ai_next = rP;
388  else aInfo.aiP4 = rP;
389  last4 = rP;
390  aInfo.aNum4++;
391  } else {
392  if (last6) last6->ai_next = rP;
393  else aInfo.aiP6 = rP;
394  last6 = rP;
395  aInfo.aNum6++;
396  }
397  rP->ai_next = 0;
398  } else {rP->ai_next = xP; xP = rP;}
399  } while((rP = nP));
400 
401 // Free any entries that we were not interested in and return
402 //
403  if (xP) freeaddrinfo(xP);
404  return 0;
405 }
406 
407 /******************************************************************************/
408 /* Private: G e t H i n t s */
409 /******************************************************************************/
410 
411 void XrdNetUtils::GetHints(XrdNetSpace::hpSpec &aInfo,
413 {
414  struct addrinfo &hints = aInfo.hints;
415 
416 // Setup the hints
417 //
418  memset(&hints, 0, sizeof(hints));
419  hints.ai_socktype = (aInfo.onlyUDP ? SOCK_DGRAM : SOCK_STREAM);
420  opts = opts & ~(onlyUDP | order46 | order64);
421  switch(opts)
422  {case allIPMap: hints.ai_family = AF_INET6;
423  hints.ai_flags = AI_V4MAPPED | AI_ALL;
424  break;
425  case allIPv64: hints.ai_family = AF_UNSPEC;
426  break;
427  case allV4Map: hints.ai_family = AF_INET;
428  aInfo.map426 = true;
429  break;
430  case onlyIPv6: hints.ai_family = AF_INET6;
431  break;
432  case onlyIPv4: hints.ai_family = AF_INET;
433  break;
434  case prefIPv6: hints.ai_family = AF_INET6;
435  hints.ai_flags = AI_V4MAPPED;
436  break;
437  case prefAuto: hints.ai_family = autoFamily;
438  hints.ai_flags = autoHints;
439  break;
440  default: hints.ai_family = AF_INET6;
441  hints.ai_flags = AI_V4MAPPED | AI_ALL;
442  break;
443  }
444 }
445 
446 /******************************************************************************/
447 /* Private: G e t H o s t P o r t */
448 /******************************************************************************/
449 
450 const char *XrdNetUtils::GetHostPort(XrdNetSpace::hpSpec &aInfo,
451  const char *hSpec, int pNum)
452 {
453  static const char *badHS = "invalid host specification";
454  const char *hnBeg, *hnEnd, *pnBeg, *pnEnd;
455 
456 // Copy the host specification
457 //
458  if (!hSpec) return badHS;
459  strlcpy(aInfo.ipAdr, hSpec, sizeof(aInfo.ipAdr));
460 
461 // Parse the host specification
462 //
463  if (pNum == NoPortRaw)
464  {hnBeg = aInfo.ipAdr;
465  aInfo.port = 0;
466  } else {
467  if (!Parse(aInfo.ipAdr, &hnBeg, &hnEnd, &pnBeg, &pnEnd)) return badHS;
468  aInfo.ipAdr[hnEnd-aInfo.ipAdr] = 0;
469  if (pnBeg == hnEnd)
470  {if (pNum == PortInSpec) return "port not specified";
471  aInfo.port = abs(pNum);
472  } else {
473  const char *eText;
474  aInfo.ipAdr[pnEnd-aInfo.ipAdr] = 0;
475  int n = ServPort(pnBeg, aInfo.onlyUDP, &eText);
476  if (!n) return eText;
477  if (pNum < 0) aInfo.port = n;
478  }
479  }
480 
481 // Check if we need to convert an ipv4 address to an ipv6 one
482 //
483  if (aInfo.hints.ai_family == AF_INET6 && aInfo.ipAdr[0] != '['
485  {memcpy(aInfo.ipMap, "::ffff:", 7);
486  aInfo.ipAddr = aInfo.ipMap;
487  } else aInfo.ipAddr = hnBeg;
488 
489 // All done
490 //
491  return 0;
492 }
493 
494 /******************************************************************************/
495 /* g e t S o k I n f o */
496 /******************************************************************************/
497 
498 int XrdNetUtils::GetSokInfo(int fd, char *theAddr, int theALen, char &theType)
499 {
500  XrdNetSockAddr theIP;
501  XrdNetAddr ipAddr;
502  static const int fmtopts = XrdNetAddrInfo::noPortRaw
504  SOCKLEN_t addrSize = sizeof(theIP);
505  int rc;
506  unsigned short thePort;
507 
508 // The the address wanted
509 //
510  rc = (fd > 0 ? getpeername( fd, &theIP.Addr, &addrSize)
511  : getsockname(-fd, &theIP.Addr, &addrSize));
512  if (rc) return -errno;
513 
514 // Set the address
515 //
516  if (ipAddr.Set(&theIP.Addr)) return -EAFNOSUPPORT;
517 
518 // Establis the type of address we have
519 //
520  if (ipAddr.isIPType(XrdNetAddrInfo::IPv4) || ipAddr.isMapped()) theType='4';
521  else theType = '6';
522 
523 // Now format the address
524 //
525  if (theAddr && theALen > 0
526  && !ipAddr.Format(theAddr, theALen, XrdNetAddrInfo::fmtAddr, fmtopts))
527  return -EINVAL;
528 
529 // Get the port number and return it.
530 //
531  thePort = htons((theIP.Addr.sa_family == AF_INET
532  ? theIP.v4.sin_port : theIP.v6.sin6_port));
533  return static_cast<int>(thePort);
534 }
535 
536 
537 /******************************************************************************/
538 /* H o s t s */
539 /******************************************************************************/
540 
541 XrdOucTList *XrdNetUtils::Hosts(const char *hSpec, int hPort, int hWant,
542  int *sPort, const char **eText)
543 {
544  static const int hMax = 8;
545  XrdNetAddr myAddr(0), aList[hMax];
546  XrdOucTList *tList = 0;
547  const char *etext, *hName;
548  int numIP, i, k;
549 
550 // Check if the port must be in the spec and set maximum
551 //
552  if (hPort < 0) hPort = XrdNetAddr::PortInSpec;
553  if (hWant > hMax) hWant = hMax;
554  else if (hWant < 1) hWant = 1;
555 
556 // Initialze the list of addresses
557 //
558  if ((etext = aList[0].Set(hSpec, numIP, hWant, hPort)))
559  {if (eText) *eText = etext;
560  return 0;
561  }
562 
563 // Create the tlist object list without duplicates. We may have duplicates as
564 // this may be a multi-homed node and we don't want to show that here.
565 //
566  for (i = 0; i < numIP; i++)
567  {if (sPort && myAddr.Same(&aList[i]))
568  {*sPort = aList[i].Port(); sPort = 0;}
569  hName = aList[i].Name("");
570  for (k = 0; k < i; k++) {if (!strcmp(hName, aList[k].Name(""))) break;}
571  if (k >= i) tList = new XrdOucTList(hName, aList[i].Port(), tList);
572  }
573 
574 // All done, return the result
575 //
576  if (eText) *eText = (tList ? 0 : "unknown processing error");
577  return tList;
578 }
579 
580 /******************************************************************************/
581 /* I P F o r m a t */
582 /******************************************************************************/
583 
584 int XrdNetUtils::IPFormat(const struct sockaddr *sAddr,
585  char *bP, int bL, int opts)
586 {
587  XrdNetAddr theAddr;
588  int fmtopts = (opts & oldFmt ? XrdNetAddrInfo::old6Map4 : 0);
589 
590 // Set the address
591 //
592  if (theAddr.Set(sAddr)) return 0;
593 
594 // Now format the address
595 //
596  if (opts & noPort) fmtopts |= XrdNetAddrInfo::noPort;
597  return theAddr.Format(bP, bL, XrdNetAddrInfo::fmtAdv6, fmtopts);
598 }
599 
600 /******************************************************************************/
601 
602 int XrdNetUtils::IPFormat(int fd, char *bP, int bL, int opts)
603 {
604  XrdNetSockAddr theIP;
605  SOCKLEN_t addrSize = sizeof(theIP);
606  int rc;
607 
608 // The the address wanted
609 //
610  rc = (fd > 0 ? getpeername( fd, &theIP.Addr, &addrSize)
611  : getsockname(-fd, &theIP.Addr, &addrSize));
612  if (rc) return 0;
613 
614 // Now format it
615 //
616  return IPFormat(&theIP.Addr, bP, bL, opts);
617 }
618 
619 /******************************************************************************/
620 /* M a t c h */
621 /******************************************************************************/
622 
623 bool XrdNetUtils::Match(const char *HostName, const char *HostPat)
624 {
625  static const int maxIP = 16;
626  const char *mval;
627  int i, j, k;
628 
629 // First check if this will match right away
630 //
631  if (!strcmp(HostPat, HostName)) return true;
632 
633 // Check for an asterisk do prefix/suffix match
634 //
635  if ((mval = index(HostPat, (int)'*')))
636  { i = mval - HostPat; mval++;
637  k = strlen(HostName); j = strlen(mval);
638  if ((i+j) > k
639  || strncmp(HostName, HostPat,i)
640  || strncmp((HostName+k-j),mval,j)) return false;
641  return 1;
642  }
643 
644 // Now check for host expansion
645 //
646  i = strlen(HostPat);
647  if (i && HostPat[i-1] == '+')
648  {XrdNetAddr InetAddr[maxIP];
649  char hBuff[264];
650  if (i >= (int)sizeof(hBuff)) return false;
651  memcpy(hBuff, HostPat, i-1);
652  hBuff[i-1] = 0;
653  if (InetAddr[0].Set(hBuff, i, maxIP, 0)) return false;
654  while(i--) if ((mval = InetAddr[i].Name()) && !strcmp(mval, HostName))
655  return true;
656  }
657 
658 // No matches
659 //
660  return false;
661 }
662 
663 /******************************************************************************/
664 /* M y H o s t N a m e */
665 /******************************************************************************/
666 
667 char *XrdNetUtils::MyHostName(const char *eName, const char **eText)
668 {
669  const char *fqn = XrdNetIdentity::FQN(eText);
670 
671 // Return the appropriate result
672 //
673  if (!fqn) fqn = eName;
674  return (fqn ? strdup(fqn) : 0);
675 }
676 
677 /******************************************************************************/
678 /* N e t C o n f i g */
679 /******************************************************************************/
680 
682  const char **eText)
683 {
684  XrdNetAddr *myAddrs;
685  const char *eMsg;
686  char buff[1024];
687  NetProt hasProt = hasNone;
688  int aCnt, ifType;
689 
690 // Make sure we support this query
691 //
692  if (netquery != qryINET && netquery != qryINIF)
693  {if (eText) *eText = "unsupported NetType query";
694  return hasNone;
695  }
696 
697 // We base the nonfig of the interface addresses unless we can't query the if's
698 //
699  if (netquery == qryINIF && (ifType = XrdNetIF::GetIF((XrdOucTList **)0,0)))
700  {if (ifType & XrdNetIF::haveIPv4) hasProt = NetProt(hasProt | hasIPv4);
701  if (ifType & XrdNetIF::haveIPv6) hasProt = NetProt(hasProt | hasIPv6);
702  if (ifType & XrdNetIF::havePub4) hasProt = NetProt(hasProt | hasPub4);
703  if (ifType & XrdNetIF::havePub6) hasProt = NetProt(hasProt | hasPub6);
704  return hasProt;
705  }
706 
707 // Get our host name and initialize this object with it
708 //
709  gethostname(buff, sizeof(buff));
710  XrdOucUtils::toLower(buff);
711 
712 // Now get all of the addresses associated with this hostname
713 //
714  if ((eMsg = GetAddrs(buff, &myAddrs, aCnt, allIPv64, NoPortRaw)))
715  {if (eText) *eText = eMsg;
716  return hasNone;
717  }
718 
719 // Now run through all of the addresses to see what we have
720 //
721  for (int i = 0; i < aCnt && hasProt != hasIP64; i++)
722  { if (myAddrs[i].isIPType(XrdNetAddrInfo::IPv6))
723  {hasProt = NetProt(hasProt | hasIPv6);
724  if (!myAddrs[i].isPrivate())
725  hasProt = NetProt(hasProt | hasPub6);
726  }
727  else if (myAddrs[i].isIPType(XrdNetAddrInfo::IPv4))
728  {hasProt = NetProt(hasProt | hasIPv4);
729  if (!myAddrs[i].isPrivate())
730  hasProt = NetProt(hasProt | hasPub4);
731  }
732  }
733 
734 // Delete the array and return what we have
735 //
736  delete [] myAddrs;
737  if (hasProt == hasNone && eText) *eText = "";
738  return hasProt;
739 }
740 
741 /******************************************************************************/
742 /* P a r s e */
743 /******************************************************************************/
744 
745 bool XrdNetUtils::Parse(const char *hSpec,
746  const char **hName, const char **hNend,
747  const char **hPort, const char **hPend)
748 {
749  const char *asep = 0;
750 
751 // Parse the specification
752 //
753  if (*hSpec == '[')
754  {if (!(*hNend = index(hSpec+1, ']'))) return false;
755  *hName = hSpec+1; asep = (*hNend)+1;
756  } else {
757  *hName = hSpec;
758  if (!(*hNend = index(hSpec, ':'))) *hNend = hSpec + strlen(hSpec);
759  else asep = *hNend;
760  }
761 
762 // See if we have a port to parse. We stop on a non-alphameric.
763 //
764  if (asep && *asep == ':')
765  {*hPort = ++asep;
766  while(isalnum(*asep)) asep++;
767  if (*hPort == asep) return false;
768  *hPend = asep;
769  } else *hPort = *hPend = *hNend;
770 
771 // All done
772 //
773  return true;
774 }
775 
776 /******************************************************************************/
777 /* P o r t */
778 /******************************************************************************/
779 
780 int XrdNetUtils::Port(int fd, const char **eText)
781 {
782  XrdNetSockAddr Inet;
783  SOCKLEN_t slen = (socklen_t)sizeof(Inet);
784  int rc;
785 
786  if ((rc = getsockname(fd, &Inet.Addr, &slen)))
787  {rc = errno;
788  if (eText) setET(eText, errno);
789  return -rc;
790  }
791 
792  return static_cast<int>(ntohs(Inet.v6.sin6_port));
793 }
794 
795 /******************************************************************************/
796 /* P r o t o I D */
797 /******************************************************************************/
798 
799 #ifndef IPPROTO_TCP
800 #define IPPROTO_TCP 6
801 #endif
802 
803 int XrdNetUtils::ProtoID(const char *pname)
804 {
805 #ifdef HAVE_PROTOR
806  struct protoent pp;
807  char buff[1024];
808 #else
809  static XrdSysMutex protomutex;
810  struct protoent *pp;
811  int protoid;
812 #endif
813 
814 // Note that POSIX did include getprotobyname_r() in the last minute. Many
815 // platforms do not document this variant but just about all include it.
816 //
817 #ifdef __solaris__
818  if (!getprotobyname_r(pname, &pp, buff, sizeof(buff)))
819  return IPPROTO_TCP;
820  return pp.p_proto;
821 #elif !defined(HAVE_PROTOR)
822  protomutex.Lock();
823  if (!(pp = getprotobyname(pname))) protoid = IPPROTO_TCP;
824  else protoid = pp->p_proto;
825  protomutex.UnLock();
826  return protoid;
827 #else
828  struct protoent *ppp;
829  if (getprotobyname_r(pname, &pp, buff, sizeof(buff), &ppp))
830  return IPPROTO_TCP;
831  return pp.p_proto;
832 #endif
833 }
834 
835 /******************************************************************************/
836 /* S e r v P o r t */
837 /******************************************************************************/
838 
839 int XrdNetUtils::ServPort(const char *sName, bool isUDP, const char **eText)
840 {
841  struct addrinfo *rP = 0, myHints;
842  int rc, portnum = 0;
843 
844 // First check if this is a plain number
845 //
846  if (isdigit(*sName))
847  {char *send;
848  portnum = strtol(sName, &send, 10);
849  if (portnum > 0 && portnum < 65536 && *send == 0) return portnum;
850  if (eText) *eText = "invalid port number";
851  return 0;
852  }
853 
854 // Fill out the hints
855 //
856  memset(&myHints, 0, sizeof(myHints));
857  myHints.ai_socktype = (isUDP ? SOCK_DGRAM : SOCK_STREAM);
858 
859 // Try to find the port number
860 //
861  rc = getaddrinfo(0, sName, &myHints, &rP);
862  if (rc || !rP)
863  {if (eText) *eText = (rc ? gai_strerror(rc) : "service not found");
864  if (rP) freeaddrinfo(rP);
865  return 0;
866  }
867 
868 // Return the port number
869 //
870  portnum = int(ntohs(SIN_PORT(rP))) & 0x0000ffff;
871  freeaddrinfo(rP);
872  if (!portnum && eText) *eText = "service has no port";
873  return portnum;
874 }
875 
876 /******************************************************************************/
877 /* S e t A u t o */
878 /******************************************************************************/
879 
881 {
882 
883 // If a specific family is not specified, then determine which families to use
884 //
885  if (aOpts != onlyIPv4 && aOpts != allIPMap)
886  {int ifTypes = XrdNetIF::GetIF(0);
887  if (ifTypes & XrdNetIF::haveIPv6) aOpts = allIPMap;
888  else if (ifTypes & XrdNetIF::haveIPv4) aOpts = onlyIPv4;
889  else {autoFamily = AF_UNSPEC; autoHints = AI_V4MAPPED | AI_ADDRCONFIG;
890  return AI_V4MAPPED | AI_ADDRCONFIG;
891  }
892  }
893 
894 // If this is forced IPv4 then we know how to set the hints
895 //
896  if (aOpts == onlyIPv4)
897  {autoFamily = AF_INET; autoHints = 0; return 0;}
898 
899 // So, this is IPv6. Be as flexible as possible.
900 //
901  autoFamily = AF_INET6;
902  autoHints = AI_V4MAPPED | AI_ALL;
903  return AI_V4MAPPED | AI_ALL;
904 }
905 
906 /******************************************************************************/
907 /* Private: s e t E T */
908 /******************************************************************************/
909 
910 int XrdNetUtils::setET(const char **errtxt, int rc)
911 {
912  if (rc) *errtxt = XrdSysE2T(rc);
913  else *errtxt = "unexpected error";
914  return 0;
915 }
916 
917 /******************************************************************************/
918 /* S i n g l e t o n */
919 /******************************************************************************/
920 
921 bool XrdNetUtils::Singleton(const char *hSpec, const char **eText)
922 {
923  XrdOucTList *hList, *hNow;
924  bool isSingle;
925 
926 // Obtain a list of unique hostnames associated with this host
927 //
928  hList = Hosts(hSpec, 1234, 2, 0, eText);
929 
930 // If this is none or only one then this is a singleton
931 //
932  isSingle = !hList || hList->next == 0;
933 
934 // Free up the list of hosts
935 //
936  while((hNow = hList))
937  {hList = hList->next;
938  delete hNow;
939  };
940 
941 // All done
942 //
943  return isSingle;
944 }
945 
946 bool XrdNetUtils::ConnectWithTimeout(int sockfd, const struct sockaddr* clientAddr,size_t clientAddrLen, uint32_t timeout_sec, std::stringstream &errMsg) {
947 
948  if (!SetSockBlocking(sockfd, false, errMsg)) { // Set to non-blocking
949  close(sockfd);
950  return false;
951  }
952 
953  int result = connect(sockfd, clientAddr, clientAddrLen);
954  if (result == 0) {
955  //We've managed to connect immediately
956  // Set the socket back to blocking
957  if(!SetSockBlocking(sockfd, true, errMsg)) {
958  ::close(sockfd);
959  return false;
960  }
961  return true;
962  } else if (errno != EINPROGRESS) {
963  errMsg << "Connection failed: " << strerror(errno);
964  ::close(sockfd);
965  return false;
966  }
967 
968  struct pollfd fds;
969  fds.fd = sockfd;
970  fds.events = POLLOUT; // Wait for the socket to be ready to write
971 
972  result = poll(&fds, 1, timeout_sec * 1000); //Timeout in milliseconds
973 
974  if (result < 0) {
975  errMsg << "Poll error: " << strerror(errno);
976  ::close(sockfd);
977  return false;
978  } else if (result == 0) {
979  errMsg << "Connection timed out";
980  ::close(sockfd);
981  return false;
982  }
983  // Polling succeeded
984  if (!(fds.revents & POLLOUT)) {
985  // We should normally not reach this code
986  errMsg << "Poll returned without error but the corresponding socket (" << sockfd << ") is not ready to write";
987  ::close(sockfd);
988  return false;
989  }
990  // Check for potential errors on the socket after polling
991  int so_error;
992  socklen_t len = sizeof(so_error);
993  getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &so_error, &len);
994  if (so_error != 0) {
995  errMsg << "Connection failed after poll: " << strerror(so_error);
996  ::close(sockfd);
997  return false;
998  }
999  // Everything succeeded, set the socket back to blocking
1000  if(!SetSockBlocking(sockfd, true, errMsg)) {
1001  ::close(sockfd);
1002  return false;
1003  }
1004  return true;
1005 }
1006 
1007 bool XrdNetUtils::SetSockBlocking(int sockfd, bool blocking, std::stringstream & errMsg) {
1008  int flags = fcntl(sockfd, F_GETFL, 0);
1009  if (flags == -1) {
1010  errMsg << "Failed to get socket flags " << strerror(errno);
1011  return false;
1012  }
1013 
1014  flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
1015 
1016  if (fcntl(sockfd, F_SETFL, flags) == -1) {
1017  errMsg << "Failed to set socket blocking/non-blocking " << strerror(errno);
1018  return false;
1019  }
1020 
1021  return true;
1022 }
struct sockaddr_in6 v6
struct sockaddr Addr
struct sockaddr_in v4
#define SIN_PORT(x)
Definition: XrdNetUtils.cc:164
#define IPPROTO_TCP
Definition: XrdNetUtils.cc:800
#define OrderXX
Definition: XrdNetUtils.cc:162
int fcntl(int fd, int cmd,...)
#define close(a)
Definition: XrdPosix.hh:43
#define eMsg(x)
struct myOpts opts
const char * XrdSysE2T(int errcode)
Definition: XrdSysE2T.cc:104
if(Avsz)
size_t strlcpy(char *dst, const char *src, size_t sz)
#define SOCKLEN_t
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)
static const int noPortRaw
Use raw address format (no port)
static const int prefipv4
Use if mapped IPV4 actual format.
bool isIPType(IPType ipType) const
int Format(char *bAddr, int bLen, fmtUse fmtType=fmtAuto, int fmtOpts=0)
@ fmtAddr
Address using suitable ipv4 or ipv6 format.
const char * Name(const char *eName=0, const char **eText=0)
int Port(int pNum=-1)
Definition: XrdNetAddr.cc:156
static const int PortInSpec
Definition: XrdNetAddr.hh:112
const char * Set(const char *hSpec, int pNum=PortInSpec)
Definition: XrdNetAddr.cc:216
static const int haveIPv4
ifList == 0 && non-local ipv4 i/f found (or'd)
Definition: XrdNetIF.hh:196
static int GetIF(XrdOucTList **ifList, const char **eText=0)
Definition: XrdNetIF.cc:429
static const int havePub6
ifList == 0 && public ipv6 i/f found (or'd)
Definition: XrdNetIF.hh:206
static const int havePub4
ifList == 0 && public ipv4 i/f found (or'd)
Definition: XrdNetIF.hh:204
static const int haveIPv6
ifList == 0 && non-local ipv6 i/f found (or'd)
Definition: XrdNetIF.hh:198
static const char * FQN(const char **etext=0)
static const char * GetAddrs(const std::string &hSpec, std::vector< XrdNetAddr > &aVec, int *ordn=0, XrdNetUtils::AddrOpts opts=XrdNetUtils::allIPMap, int pNum=XrdNetUtils::PortInSpec)
static const char pfx
Registry names must start with this character.
static bool Match(const char *hName, const char *pattern)
Definition: XrdNetUtils.cc:623
static char * MyHostName(const char *eName="*unknown*", const char **eText=0)
Definition: XrdNetUtils.cc:667
static int GetSokInfo(int fd, char *theAddr, int theALen, char &theType)
Definition: XrdNetUtils.cc:498
static int Encode(const XrdNetSockAddr *sadr, char *buff, int blen, int port=-1)
Definition: XrdNetUtils.cc:120
static int IPFormat(const struct sockaddr *sAddr, char *bP, int bL, int opts=0)
Definition: XrdNetUtils.cc:584
static bool Singleton(const char *hSpec, const char **eText=0)
Definition: XrdNetUtils.cc:921
static const char * GetAddrs(const char *hSpec, XrdNetAddr *aListP[], int &aListN, AddrOpts opts=allIPMap, int pNum=PortInSpec)
Definition: XrdNetUtils.cc:239
static int Decode(XrdNetSockAddr *sadr, const char *buff, int blen)
Definition: XrdNetUtils.cc:70
static NetProt NetConfig(NetType netquery=qryINET, const char **eText=0)
Definition: XrdNetUtils.cc:681
static bool ConnectWithTimeout(int sockfd, const struct sockaddr *clientAddr, size_t clientAddrLen, uint32_t timeout_sec, std::stringstream &errMsg)
Definition: XrdNetUtils.cc:946
static int Port(int fd, const char **eText=0)
Definition: XrdNetUtils.cc:780
static int ProtoID(const char *pName)
Definition: XrdNetUtils.cc:803
static int ServPort(const char *sName, bool isUDP=false, const char **eText=0)
Definition: XrdNetUtils.cc:839
static XrdOucTList * Hosts(const char *hSpec, int hPort=-1, int hWant=8, int *sPort=0, const char **eText=0)
Definition: XrdNetUtils.cc:541
static bool Parse(const char *hSpec, const char **hName, const char **hNend, const char **hPort, const char **hPend)
Definition: XrdNetUtils.cc:745
static int SetAuto(AddrOpts aOpts=allIPMap)
Definition: XrdNetUtils.cc:880
XrdOucTList * next
Definition: XrdOucTList.hh:45
static void toLower(char *str)
const char * ipAddr
Definition: XrdNetUtils.cc:168
char ipAdr[MAXHOSTNAMELEN+15]
Definition: XrdNetUtils.cc:180
hpSpec(XrdNetUtils::AddrOpts opts)
Definition: XrdNetUtils.cc:182