00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 const char *XrdNetDNSCVSID = "$Id: XrdNetDNS.cc 35287 2010-09-14 21:19:35Z ganis $";
00014
00015 #include <ctype.h>
00016 #include <errno.h>
00017 #include <stdlib.h>
00018 #include <string.h>
00019 #ifndef WIN32
00020 #include <netdb.h>
00021 #include <strings.h>
00022 #include <stdio.h>
00023 #include <unistd.h>
00024 #include <sys/socket.h>
00025 #include <netinet/in.h>
00026 #include <arpa/inet.h>
00027 #endif
00028
00029 #include "XrdNet/XrdNetDNS.hh"
00030 #include "XrdSys/XrdSysHeaders.hh"
00031 #include "XrdSys/XrdSysPlatform.hh"
00032 #include "XrdSys/XrdSysPthread.hh"
00033
00034
00035
00036
00037
00038 int XrdNetDNS::getHostAddr(const char *InetName,
00039 struct sockaddr InetAddr[],
00040 int maxipa,
00041 char **errtxt)
00042 {
00043 #ifdef HAVE_NAMEINFO
00044 struct addrinfo *rp, *np, *pnp=0;
00045 struct addrinfo myhints = {AI_CANONNAME};
00046 #else
00047 unsigned int addr;
00048 struct hostent hent, *hp;
00049 char **p, hbuff[1024];
00050 #endif
00051 struct sockaddr_in *ip;
00052 int i, rc;
00053
00054
00055
00056 if (!InetName || !InetName[0])
00057 {ip = (struct sockaddr_in *)&InetAddr[0];
00058 ip->sin_family = AF_INET;
00059 ip->sin_port = 0;
00060 ip->sin_addr.s_addr = INADDR_ANY;
00061 memset((void *)ip->sin_zero, 0, sizeof(ip->sin_zero));
00062 return 1;
00063 }
00064
00065
00066
00067 rc = 0;
00068 #ifndef HAVE_NAMEINFO
00069 if (!isdigit((int)*InetName))
00070 #ifdef __solaris__
00071 gethostbyname_r(InetName, &hent, hbuff, sizeof(hbuff), &rc);
00072 #else
00073 gethostbyname_r(InetName, &hent, hbuff, sizeof(hbuff), &hp, &rc);
00074 #endif
00075 else if ((int)(addr = inet_addr(InetName)) == -1)
00076 return (errtxt ? setET(errtxt, EINVAL) : 0);
00077 #ifdef __solaris__
00078 else gethostbyaddr_r(&addr,sizeof(addr), AF_INET, &hent,
00079 hbuff, sizeof(hbuff), &rc);
00080 #else
00081 else gethostbyaddr_r((char *)&addr,sizeof(addr), AF_INET, &hent,
00082 hbuff, sizeof(hbuff), &hp, &rc);
00083 #endif
00084 if (rc) return (errtxt ? setET(errtxt, rc) : 0);
00085
00086
00087
00088 for (i = 0, p = hent.h_addr_list; *p != 0 && i < maxipa; p++, i++)
00089 {ip = (struct sockaddr_in *)&InetAddr[i];
00090 memcpy((void *)&(ip->sin_addr), (const void *)*p, sizeof(ip->sin_addr));
00091 ip->sin_port = 0;
00092 ip->sin_family = hent.h_addrtype;
00093 memset((void *)ip->sin_zero, 0, sizeof(ip->sin_zero));
00094 }
00095
00096 #else
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106 myhints.ai_family = AF_INET;
00107
00108
00109
00110
00111 if (isdigit((int)*InetName)) myhints.ai_flags |= AI_NUMERICHOST;
00112 rc = getaddrinfo(InetName,0,(const addrinfo *)&myhints, &rp);
00113 if (rc || !(np = rp)) return (errtxt ? setETni(errtxt, rc) : 0);
00114
00115
00116
00117
00118
00119 i = 0;
00120 do {if (!pnp
00121 || memcmp((const void *)pnp->ai_addr, (const void *)np->ai_addr,
00122 sizeof(struct sockaddr)))
00123 memcpy((void *)&InetAddr[i++], (const void *)np->ai_addr,
00124 sizeof(struct sockaddr));
00125 pnp = np; np = np->ai_next;
00126 } while(i < maxipa && np);
00127 freeaddrinfo(rp);
00128
00129 #endif
00130
00131
00132
00133 return i;
00134 }
00135
00136
00137
00138
00139
00140
00141 int XrdNetDNS::getAddrName(const char *InetName,
00142 int maxipa, char **Addr, char **Name,
00143 char **errtxt)
00144 {
00145
00146
00147
00148 if (!InetName || !Addr || !Name) return 0;
00149
00150
00151
00152 maxipa = (maxipa > 1 && maxipa <= 10) ? maxipa : 1;
00153
00154
00155 struct sockaddr_in ip[10];
00156 int n = XrdNetDNS::getHostAddr(InetName,(struct sockaddr *)ip, maxipa, errtxt);
00157
00158
00159 int i = 0;
00160 for (; i < n; i++ ) {
00161
00162
00163 char buf[255];
00164 inet_ntop(ip[i].sin_family, &ip[i].sin_addr, buf, sizeof(buf));
00165 Addr[i] = strdup(buf);
00166
00167
00168 char *names[1] = {0};
00169 int hn = getHostName((struct sockaddr &)ip[i], names, 1, errtxt);
00170 if (hn)
00171 Name[i] = strdup(names[0]);
00172 else
00173 Name[i] = strdup(Addr[i]);
00174
00175
00176 if (names[0]) free(names[0]);
00177 }
00178
00179
00180 return n;
00181 }
00182
00183
00184
00185
00186
00187 char *XrdNetDNS::getHostID(struct sockaddr &InetAddr)
00188 {
00189 struct sockaddr_in *ip = (sockaddr_in *)&InetAddr;
00190 char mybuff[256];
00191 char *hname;
00192
00193
00194
00195 hname = (char *)inet_ntop(ip->sin_family,
00196 (const void *)(&ip->sin_addr),
00197 mybuff, sizeof(mybuff));
00198 return (hname ? strdup(hname) : strdup("0.0.0.0"));
00199 }
00200
00201
00202
00203
00204
00205 char *XrdNetDNS::getHostName(const char *InetName, char **errtxt)
00206 {
00207 char myname[256];
00208 const char *hp;
00209 struct sockaddr InetAddr;
00210
00211
00212
00213 if (InetName) hp = InetName;
00214 else if (gethostname(myname, sizeof(myname)))
00215 {if (errtxt) setET(errtxt, errno); return strdup("0.0.0.0");}
00216 else hp = myname;
00217
00218
00219
00220 if (!getHostAddr(hp, InetAddr, errtxt)) return strdup("0.0.0.0");
00221
00222
00223
00224 return getHostName(InetAddr, errtxt);
00225 }
00226
00227
00228
00229
00230
00231 char *XrdNetDNS::getHostName(struct sockaddr &InetAddr, char **errtxt)
00232 {
00233 char *result;
00234 if (getHostName(InetAddr, &result, 1, errtxt)) return result;
00235
00236 {char dnbuff[64];
00237 unsigned int ipaddr;
00238 struct sockaddr_in *ip = (sockaddr_in *)&InetAddr;
00239 memcpy(&ipaddr, &ip->sin_addr, sizeof(ipaddr));
00240 IP2String(ipaddr, -1, dnbuff, sizeof(dnbuff));
00241 return strdup(dnbuff);
00242 }
00243 }
00244
00245
00246
00247
00248
00249 int XrdNetDNS::getHostName(struct sockaddr &InetAddr,
00250 char *InetName[],
00251 int maxipn,
00252 char **errtxt)
00253 {
00254 char mybuff[256];
00255 int i, rc;
00256
00257
00258
00259 if (errtxt) *errtxt = 0;
00260
00261
00262
00263
00264 #if defined(HAVE_NAMEINFO) && !defined(__macos__)
00265 struct addrinfo *rp, *np;
00266 struct addrinfo myhints = {AI_CANONNAME};
00267 #elif defined(HAVE_GETHBYXR)
00268 struct sockaddr_in *ip = (sockaddr_in *)&InetAddr;
00269 struct hostent hent, *hp;
00270 char *hname, hbuff[1024];
00271 #else
00272 static XrdSysMutex getHN;
00273 XrdSysMutexHelper getHNhelper;
00274 struct sockaddr_in *ip = (sockaddr_in *)&InetAddr;
00275 struct hostent *hp;
00276 unsigned int ipaddr;
00277 char *hname;
00278 #endif
00279
00280
00281
00282 if (maxipn < 1) return (errtxt ? setET(errtxt, EINVAL) : 0);
00283
00284
00285
00286 if (InetAddr.sa_family == AF_UNIX)
00287 {InetName[0] = strdup("localhost"); return 1;}
00288
00289 #if !defined(HAVE_NAMEINFO) || defined(__macos__)
00290
00291
00292
00293 rc = 0;
00294 #ifdef HAVE_GETHBYXR
00295 #ifdef __solaris__
00296 gethostbyaddr_r(&(ip->sin_addr), sizeof(struct in_addr),
00297 AF_INET, &hent, hbuff, sizeof(hbuff), &rc);
00298 hp = &hent;
00299 #else
00300 gethostbyaddr_r(&(ip->sin_addr), sizeof(struct in_addr),
00301 AF_INET, &hent, hbuff, sizeof(hbuff), &hp, &rc);
00302 #endif
00303 #else
00304 memcpy(&ipaddr, &ip->sin_addr, sizeof(ipaddr));
00305 getHNhelper.Lock(&getHN);
00306 if (!(hp=gethostbyaddr((const char *)&ipaddr, sizeof(InetAddr), AF_INET)))
00307 rc = (h_errno ? h_errno : EINVAL);
00308 #endif
00309
00310 if (rc)
00311 {hname = (char *)inet_ntop(ip->sin_family,
00312 (const void *)(&ip->sin_addr),
00313 mybuff, sizeof(mybuff));
00314 if (!hname) return (errtxt ? setET(errtxt, errno) : 0);
00315 InetName[0] = strdup(hname);
00316 return 1;
00317 }
00318
00319
00320
00321 InetName[0] = LowCase(strdup(hp->h_name));
00322
00323
00324
00325 hname = *hp->h_aliases;
00326 for (i = 1; i < maxipn && hname; i++, hname++)
00327 InetName[i] = LowCase(strdup(hname));
00328 #else
00329
00330
00331
00332
00333 if ((rc = getnameinfo(&InetAddr, sizeof(struct sockaddr),
00334 mybuff, sizeof(mybuff), 0, 0, 0)))
00335 return (errtxt ? setETni(errtxt, rc) : 0);
00336
00337
00338
00339 if (maxipn < 2)
00340 {InetName[0] = LowCase(strdup(mybuff));
00341 return 1;
00342 }
00343
00344
00345
00346
00347
00348
00349
00350 myhints.ai_family = AF_INET;
00351
00352
00353
00354 rc = getaddrinfo(mybuff,0,(const addrinfo *)&myhints, &rp);
00355 if (rc || !(np = rp)) return (errtxt ? setETni(errtxt, rc) : 0);
00356
00357
00358
00359 for (i = 0; i < maxipn && np; i++)
00360 {InetName[i] = LowCase(strdup(np->ai_canonname));
00361 np = np->ai_next;
00362 }
00363 freeaddrinfo(rp);
00364
00365 #endif
00366
00367
00368
00369 return i;
00370 }
00371
00372
00373
00374
00375
00376 int XrdNetDNS::getPort(const char *servname,
00377 const char *servtype,
00378 char **errtxt)
00379 {
00380 int rc;
00381
00382 #ifdef HAVE_NAMEINFO
00383 struct addrinfo *rp, *np;
00384 struct addrinfo myhints = {0};
00385 int portnum = 0;
00386 #else
00387 struct servent sent, *sp;
00388 char sbuff[1024];
00389 #endif
00390
00391
00392
00393 #ifndef HAVE_NAMEINFO
00394 #ifdef __solaris__
00395 if ( !getservbyname_r(servname,servtype,&sent,sbuff,sizeof(sbuff)))
00396 return (errtxt ? setET(errtxt, errno) : 0);
00397 #else
00398 if ((rc=getservbyname_r(servname,servtype,&sent,sbuff,sizeof(sbuff),&sp)))
00399 return (errtxt ? setET(errtxt, rc) : 0);
00400 #endif
00401 return int(ntohs(sent.s_port));
00402 #else
00403 if ((rc = getaddrinfo(0,servname,(const struct addrinfo *)&myhints,&rp))
00404 || !(np = rp)) return (errtxt ? setETni(errtxt, rc) : 0);
00405
00406 while(np) if (np->ai_socktype == SOCK_STREAM && *servtype == 't') break;
00407 else if (np->ai_socktype == SOCK_DGRAM && *servtype == 'u') break;
00408 else np = np->ai_next;
00409 if (np) portnum=int(ntohs(((struct sockaddr_in *)(np->ai_addr))->sin_port));
00410 freeaddrinfo(rp);
00411 if (!portnum) return (errtxt ? setET(errtxt, ESRCH) : 0);
00412 return portnum;
00413 #endif
00414 }
00415
00416
00417
00418 int XrdNetDNS::getPort(int fd, char **errtxt)
00419 {
00420 struct sockaddr InetAddr;
00421 struct sockaddr_in *ip = (struct sockaddr_in *)&InetAddr;
00422 socklen_t slen = (socklen_t)sizeof(InetAddr);
00423 int rc;
00424
00425 if ((rc = getsockname(fd, &InetAddr, &slen)))
00426 {rc = errno;
00427 if (errtxt) setET(errtxt, errno);
00428 return -rc;
00429 }
00430
00431 return static_cast<int>(ntohs(ip->sin_port));
00432 }
00433
00434
00435
00436
00437
00438 #define NET_IPPROTO_TCP 6
00439
00440 int XrdNetDNS::getProtoID(const char *pname)
00441 {
00442 #ifdef HAVE_PROTOR
00443 struct protoent pp;
00444 char buff[1024];
00445 #else
00446 static XrdSysMutex protomutex;
00447 struct protoent *pp;
00448 int protoid;
00449 #endif
00450
00451
00452
00453
00454 #ifdef __solaris__
00455 if (!getprotobyname_r(pname, &pp, buff, sizeof(buff)))
00456 return NET_IPPROTO_TCP;
00457 return pp.p_proto;
00458 #elif !defined(HAVE_PROTOR)
00459 protomutex.Lock();
00460 if (!(pp = getprotobyname(pname))) protoid = NET_IPPROTO_TCP;
00461 else protoid = pp->p_proto;
00462 protomutex.UnLock();
00463 return protoid;
00464 #else
00465 struct protoent *ppp;
00466 if (getprotobyname_r(pname, &pp, buff, sizeof(buff), &ppp))
00467 return NET_IPPROTO_TCP;
00468 return pp.p_proto;
00469 #endif
00470 }
00471
00472
00473
00474
00475
00476 int XrdNetDNS::Host2Dest(const char *hostname,
00477 struct sockaddr &DestAddr,
00478 char **errtxt)
00479 { char *cp, hbuff[256];
00480 int port, i;
00481 struct sockaddr_in InetAddr;
00482
00483
00484
00485 if (!(cp = (char *) index(hostname, (int)':')))
00486 {if (errtxt) *errtxt = (char *)"port not specified";
00487 return 0;
00488 }
00489
00490
00491
00492 if ((i = cp-hostname) >= static_cast<int>(sizeof(hbuff)))
00493 {if (errtxt) *errtxt = (char *)"hostname too long";
00494 return 0;
00495 }
00496 strlcpy(hbuff, hostname, i+1);
00497
00498
00499
00500 if (!getHostAddr(hbuff, (struct sockaddr &)InetAddr, errtxt)) return 0;
00501
00502
00503
00504 if (!(port = atoi(cp+1)) || port > 0xffff)
00505 {if (errtxt) *errtxt = (char *)"invalid port number";
00506 return 0;
00507 }
00508
00509
00510
00511 InetAddr.sin_family = AF_INET;
00512 InetAddr.sin_port = htons(port);
00513 memcpy((void *)&DestAddr, (const void *)&InetAddr, sizeof(sockaddr));
00514 memset((void *)&InetAddr.sin_zero, 0, sizeof(InetAddr.sin_zero));
00515 return 1;
00516 }
00517
00518
00519
00520
00521
00522 int XrdNetDNS::Host2IP(const char *hname, unsigned int *ipaddr)
00523 {
00524 struct sockaddr_in InetAddr;
00525
00526
00527
00528 if (!getHostAddr(hname, (struct sockaddr &)InetAddr)) return 0;
00529 if (ipaddr) memcpy(ipaddr, &InetAddr.sin_addr, sizeof(unsigned int));
00530 return 1;
00531 }
00532
00533
00534
00535
00536
00537 unsigned int XrdNetDNS::IPAddr(struct sockaddr *InetAddr)
00538 {return (unsigned int)(((struct sockaddr_in *)InetAddr)->sin_addr.s_addr);}
00539
00540
00541
00542
00543
00544 int XrdNetDNS::IP2String(unsigned int ipaddr, int port, char *buff, int blen)
00545 {
00546 struct in_addr in;
00547 int sz;
00548
00549
00550
00551 in.s_addr = ipaddr;
00552 if (port <= 0)
00553 sz = snprintf(buff,blen,"%s", inet_ntoa((const struct in_addr)in));
00554 else
00555 sz = snprintf(buff,blen,"%s:%d",inet_ntoa((const struct in_addr)in),port);
00556 return (sz > blen ? blen : sz);
00557 }
00558
00559
00560
00561
00562
00563 int XrdNetDNS::isDomain(const char *Hostname, const char *Domname, int Domlen)
00564 {
00565 int hlen = strlen(Hostname);
00566
00567 return (hlen >= Domlen && !strcmp(Hostname+(hlen-Domlen), Domname));
00568 }
00569
00570
00571
00572
00573
00574 int XrdNetDNS::isLoopback(struct sockaddr &InetAddr)
00575 {
00576 struct sockaddr_in *ip = (struct sockaddr_in *)&InetAddr;
00577 return ip->sin_addr.s_addr == 0x7f000001;
00578 }
00579
00580
00581
00582
00583
00584 int XrdNetDNS::isMatch(const char *HostName, char *HostPat)
00585 {
00586 struct sockaddr InetAddr[16];
00587 char *mval;
00588 int i, j, k, retc;
00589
00590 if (!strcmp(HostPat, HostName)) return 1;
00591
00592 if ((mval = index(HostPat, (int)'*')))
00593 {*mval = '\0'; mval++;
00594 k = strlen(HostName); j = strlen(mval); i = strlen(HostPat);
00595 if ((i+j) > k
00596 || strncmp(HostName, HostPat,i)
00597 || strncmp((HostName+k-j),mval,j)) return 0;
00598 return 1;
00599 }
00600
00601 i = strlen(HostPat);
00602 if (HostPat[i-1] != '+') i = 0;
00603 else {HostPat[i-1] = '\0';
00604 if (!(i = getHostAddr(HostPat, InetAddr, 16)))
00605 return 0;
00606 }
00607
00608 while(i--)
00609 {mval = getHostName(InetAddr[i]);
00610 retc = !strcmp(mval,HostName);
00611 free(mval);
00612 if (retc) return 1;
00613 }
00614 return 0;
00615 }
00616
00617
00618
00619
00620
00621 char *XrdNetDNS::Peername(int snum, struct sockaddr *sap, char **errtxt)
00622 {
00623 struct sockaddr addr;
00624 SOCKLEN_t addrlen = sizeof(addr);
00625
00626
00627
00628 if (!sap) sap = &addr;
00629 if (getpeername(snum, (struct sockaddr *)sap, &addrlen) < 0)
00630 {if (errtxt) setET(errtxt, errno);
00631 return (char *)0;
00632 }
00633
00634
00635
00636 return getHostName(*sap, errtxt);
00637 }
00638
00639
00640
00641
00642
00643 void XrdNetDNS::setPort(struct sockaddr &InetAddr, int port, int anyaddr)
00644 {
00645 unsigned short int sport = static_cast<unsigned short int>(port);
00646 struct sockaddr_in *ip = (struct sockaddr_in *)&InetAddr;
00647 ip->sin_port = htons(sport);
00648 if (anyaddr) {ip->sin_family = AF_INET;
00649 ip->sin_addr.s_addr = INADDR_ANY;
00650 memset((void *)ip->sin_zero, 0, sizeof(ip->sin_zero));
00651 }
00652 }
00653
00654
00655
00656
00657
00658
00659
00660
00661 char *XrdNetDNS::LowCase(char *str)
00662 {
00663 char *sp = str;
00664
00665 while(*sp) {if (isupper((int)*sp)) *sp = (char)tolower((int)*sp); sp++;}
00666
00667 return str;
00668 }
00669
00670
00671
00672
00673
00674 int XrdNetDNS::setET(char **errtxt, int rc)
00675 {
00676 if (rc) *errtxt = strerror(rc);
00677 else *errtxt = (char *)"unexpected error";
00678 return 0;
00679 }
00680
00681
00682
00683
00684
00685 int XrdNetDNS::setETni(char **errtxt, int rc)
00686 {
00687 #ifndef HAVE_NAMEINFO
00688 return setET(errtxt, rc);
00689 #else
00690 if (rc) *errtxt = (char *)gai_strerror(rc);
00691 else *errtxt = (char *)"unexpected error";
00692 return 0;
00693 #endif
00694 }