MyString get_hostname(const condor_sockaddr& addr) { MyString ret; if (nodns_enabled()) return convert_ipaddr_to_hostname(addr); condor_sockaddr targ_addr; // just like sin_to_string(), if given address is 0.0.0.0 or equivalent, // it changes to local IP address. if (addr.is_addr_any()) targ_addr = get_local_ipaddr(addr.get_protocol()); else targ_addr = addr; int e; char hostname[NI_MAXHOST]; // if given address is link-local IPv6 address, it will have %NICname // at the end of string // we would like to avoid it if (targ_addr.is_ipv6()) targ_addr.set_scope_id(0); e = condor_getnameinfo(targ_addr, hostname, sizeof(hostname), NULL, 0, 0); if (e) return ret; ret = hostname; return ret; }
// This is obsolete function. do not use. struct hostent * condor_gethostbyaddr_ipv6(const char *addr, SOCKET_LENGTH_TYPE len, int type) { char _hostname[NI_MAXHOST]; struct sockaddr_in sinaddr; int e; MSC_SUPPRESS_WARNING(6287) // warning: Redundant code: the left and right sub-expressions are identical if (type != AF_INET || type != PF_INET) { // fallback return condor_gethostbyaddr_ipv4(addr, len, type); } if (nodns_enabled()) { return get_nodns_addr(addr); } memset(&sinaddr, 0, sizeof(sinaddr)); sinaddr.sin_family = type; sinaddr.sin_addr = *(const struct in_addr*)addr; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sinaddr.sin_len = sizeof(struct sockaddr_in); #endif e = getnameinfo((const struct sockaddr*)&sinaddr, sizeof(sinaddr), _hostname, sizeof(_hostname), NULL, 0, 0); if (e != 0) return NULL; // getnameinfo only returns hostname. in order to fill up struct hostent, call condor_gethotsbyname_ipv6 return condor_gethostbyname_ipv6(_hostname); }
std::vector<MyString> get_hostname_with_alias(const condor_sockaddr& addr) { std::vector<MyString> ret; MyString hostname = get_hostname(addr); if (hostname.IsEmpty()) return ret; ret.push_back(hostname); if (nodns_enabled()) return ret; // no need to call further DNS functions. hostent* ent; //int aftype = addr.get_aftype(); //ent = gethostbyname2(hostname.Value(), addr.get_aftype()); // really should call gethostbyname2() however most platforms do not // support. (Solaris, HP-UX, IRIX) // complete DNS aliases can be only obtained by gethostbyname. // however, what happens if we call it in IPv6-only system? // can we get DNS aliases for the hostname that only contains // IPv6 addresses? ent = gethostbyname(hostname.Value()); if (!ent) return ret; char** alias = ent->h_aliases; for (; *alias; ++alias) { ret.push_back(MyString(*alias)); } return ret; }
struct hostent * condor_gethostbyname_ipv4(const char *name) { if (nodns_enabled()) { return get_nodns_hostent(name); } else { return gethostbyname(name); } }
struct hostent * condor_gethostbyaddr_ipv4(const char *addr, SOCKET_LENGTH_TYPE len, int type) { if (nodns_enabled()) { return get_nodns_addr(addr); } else { return gethostbyaddr(addr, len, type); } }
std::vector<MyString> get_hostname_with_alias(const condor_sockaddr& addr) { std::vector<MyString> prelim_ret; std::vector<MyString> actual_ret; MyString hostname = get_hostname(addr); if (hostname.IsEmpty()) return prelim_ret; // we now start to construct a list (prelim_ret) of the hostname and all // the aliases. first the name itself. prelim_ret.push_back(hostname); if (nodns_enabled()) // don't need to verify this... the string is actually an IP here return prelim_ret; // no need to call further DNS functions. // now, add the aliases hostent* ent; //int aftype = addr.get_aftype(); //ent = gethostbyname2(hostname.Value(), addr.get_aftype()); // really should call gethostbyname2() however most platforms do not // support. (Solaris, HP-UX, IRIX) // complete DNS aliases can be only obtained by gethostbyname. // however, what happens if we call it in IPv6-only system? // can we get DNS aliases for the hostname that only contains // IPv6 addresses? ent = gethostbyname(hostname.Value()); if (ent) { char** alias = ent->h_aliases; for (; *alias; ++alias) { prelim_ret.push_back(MyString(*alias)); } } // WARNING! there is a reason this is implimented as two separate loops, // so please don't try to combine them. // // calling verify_name_has_ip() will potentially overwrite static data that // is referred to by ent->h_aliases (man 3 gethostbyname, see notes). so // first, we push the name and then all aliases into the MyString vector // prelim_ret, and then verify them in the following loop. for (unsigned int i = 0; i < prelim_ret.size(); i++) { if(verify_name_has_ip(prelim_ret[i], addr)) { actual_ret.push_back(prelim_ret[i]); } else { dprintf(D_ALWAYS, "WARNING: forward resolution of %s doesn't match %s!\n", prelim_ret[i].Value(), addr.to_ip_string().Value()); } } return actual_ret; }
std::vector<condor_sockaddr> resolve_hostname(const MyString& hostname) { std::vector<condor_sockaddr> ret; if (nodns_enabled()) { condor_sockaddr addr = convert_hostname_to_ipaddr(hostname); if (addr == condor_sockaddr::null) return ret; ret.push_back(addr); return ret; } return resolve_hostname_raw(hostname); }
MyString get_fqdn_from_hostname(const MyString& hostname) { if (hostname.FindChar('.') != -1) return hostname; MyString ret; if (!nodns_enabled()) { addrinfo_iterator ai; int res = ipv6_getaddrinfo(hostname.Value(), NULL, ai); if (res) { dprintf(D_HOSTNAME, "ipv6_getaddrinfo() could not look up %s: %s (%d)\n", hostname.Value(), gai_strerror(res), res); return ret; } while (addrinfo* info = ai.next()) { if (info->ai_canonname) { if (strchr(info->ai_canonname, '.')) return info->ai_canonname; } } hostent* h = gethostbyname(hostname.Value()); if (h && h->h_name && strchr(h->h_name, '.')) { return h->h_name; } if (h && h->h_aliases && *h->h_aliases) { for (char** alias = h->h_aliases; *alias; ++alias) { if (strchr(*alias, '.')) return *alias; } } } MyString default_domain; if (param(default_domain, "DEFAULT_DOMAIN_NAME")) { ret = hostname; if (ret[ret.Length() - 1] != '.') ret += "."; ret += default_domain; } return ret; }
bool init_local_hostname_impl() { bool local_hostname_initialized = false; if (param(local_hostname, "NETWORK_HOSTNAME")) { local_hostname_initialized = true; dprintf(D_HOSTNAME, "NETWORK_HOSTNAME says we are %s\n", local_hostname.Value()); } if( ! local_hostname_initialized ) { // [TODO:IPV6] condor_gethostname is not IPv6 safe. Reimplement it. char hostname[MAXHOSTNAMELEN]; int ret = condor_gethostname(hostname, sizeof(hostname)); if (ret) { dprintf(D_ALWAYS, "condor_gethostname() failed. Cannot initialize " "local hostname, ip address, FQDN.\n"); return false; } local_hostname = hostname; } MyString test_hostname = local_hostname; bool local_ipaddr_initialized = false; bool local_ipv4addr_initialized = false; bool local_ipv6addr_initialized = false; MyString network_interface; if (param(network_interface, "NETWORK_INTERFACE")) { if(local_ipaddr_initialized == false && local_ipaddr.from_ip_string(network_interface)) { local_ipaddr_initialized = true; if(local_ipaddr.is_ipv4()) { local_ipv4addr = local_ipaddr; local_ipv4addr_initialized = true; } if(local_ipaddr.is_ipv6()) { local_ipv6addr = local_ipaddr; local_ipv6addr_initialized = true; } } } if( ! local_ipaddr_initialized ) { std::string ipv4, ipv6, ipbest; if( network_interface_to_ip("NETWORK_INTERFACE", network_interface.Value(), ipv4, ipv6, ipbest, NULL)) { ASSERT(local_ipaddr.from_ip_string(ipbest)); // If this fails, network_interface_to_ip returns something invalid. local_ipaddr_initialized = true; } else { dprintf(D_ALWAYS, "Unable to identify IP address from interfaces. None match NETWORK_INTERFACE=%s. Problems are likely.\n", network_interface.Value()); } if((!ipv4.empty()) && local_ipv4addr.from_ip_string(ipv4)) { local_ipv4addr_initialized = true; ASSERT(local_ipv4addr.is_ipv4()); } if((!ipv6.empty()) && local_ipv6addr.from_ip_string(ipv6)) { local_ipv6addr_initialized = true; ASSERT(local_ipv6addr.is_ipv6()); } } bool local_fqdn_initialized = false; if (nodns_enabled()) { // condor_gethostname() returns a hostname with // DEFAULT_DOMAIN_NAME. Thus, it is always fqdn local_fqdn = local_hostname; local_fqdn_initialized = true; if (!local_ipaddr_initialized) { local_ipaddr = convert_hostname_to_ipaddr(local_hostname); local_ipaddr_initialized = true; } } addrinfo_iterator ai; if( ! nodns_enabled() ) { const int MAX_TRIES = 20; const int SLEEP_DUR = 3; bool gai_success = false; for(int try_count = 1; true; try_count++) { addrinfo hint = get_default_hint(); hint.ai_family = AF_UNSPEC; int ret = ipv6_getaddrinfo(test_hostname.Value(), NULL, ai, hint); if(ret == 0) { gai_success = true; break; } if(ret != EAI_AGAIN ) { dprintf(D_ALWAYS, "init_local_hostname_impl: ipv6_getaddrinfo() could not look up '%s': %s (%d). Error is not recoverable; giving up. Problems are likely.\n", test_hostname.Value(), gai_strerror(ret), ret ); gai_success = false; break; } dprintf(D_ALWAYS, "init_local_hostname_impl: ipv6_getaddrinfo() returned EAI_AGAIN for '%s'. Will try again after sleeping %d seconds (try %d of %d).\n", test_hostname.Value(), SLEEP_DUR, try_count + 1, MAX_TRIES ); if(try_count == MAX_TRIES) { dprintf(D_ALWAYS, "init_local_hostname_impl: ipv6_getaddrinfo() never succeeded. Giving up. Problems are likely\n"); break; } sleep(SLEEP_DUR); } if(gai_success) { int local_hostname_desireability = 0; #ifdef TEST_DNS_TODO int local_ipaddr_desireability = 0; int local_ipv4addr_desireability = 0; int local_ipv6addr_desireability = 0; #endif while (addrinfo* info = ai.next()) { // TODO: the only time ai_canonname should be set is the first // record. Why are we testing its desirability? const char* name = info->ai_canonname; if (!name) continue; condor_sockaddr addr(info->ai_addr); int desireability = addr.desirability(); const char * result = "skipped for low score"; if(desireability > local_hostname_desireability) { result = "new winner"; dprintf(D_HOSTNAME, " I like it.\n"); local_hostname_desireability = desireability; const char* dotpos = strchr(name, '.'); if (dotpos) { // consider it as a FQDN local_fqdn = name; local_hostname = local_fqdn.Substr(0, dotpos-name-1); } else { local_hostname = name; local_fqdn = local_hostname; MyString default_domain; if (param(default_domain, "DEFAULT_DOMAIN_NAME")) { if (default_domain[0] != '.') local_fqdn += "."; local_fqdn += default_domain; } } } dprintf(D_HOSTNAME, "hostname: %s (score %d) %s\n", name, desireability, result); #ifdef TEST_DNS_TODO // Resist urge to set local_ip*addr_initialized=true, // We want to repeatedly retest this looking for // better results. if (!local_ipaddr_initialized) { replace_higher_scoring_addr("IP", local_ipaddr, local_ipaddr_desireability, addr, desireability); } if (addr.is_ipv4() && !local_ipv4addr_initialized) { replace_higher_scoring_addr("IPv4", local_ipv4addr, local_ipv4addr_desireability, addr, desireability); } if (addr.is_ipv6() && !local_ipv6addr_initialized) { replace_higher_scoring_addr("IPv6", local_ipv6addr, local_ipv6addr_desireability, addr, desireability); } #else // Make Fedora quit complaining. if( local_ipv4addr_initialized && local_ipv6addr_initialized && local_fqdn_initialized ) { local_ipv4addr_initialized = false; local_ipv6addr_initialized = false; local_fqdn_initialized = false; } #endif } } } return true; }
int get_fqdn_and_ip_from_hostname(const MyString& hostname, MyString& fqdn, condor_sockaddr& addr) { MyString ret; condor_sockaddr ret_addr; bool found_ip = false; // if the hostname contains dot, hostname is assumed to be full hostname if (hostname.FindChar('.') != -1) { ret = hostname; } if (nodns_enabled()) { // if nodns is enabled, convert hostname to ip address directly ret_addr = convert_hostname_to_ipaddr(hostname); found_ip = true; } else { // we look through getaddrinfo and gethostbyname // to further seek fully-qualified domain name and corresponding // ip address addrinfo_iterator ai; int res = ipv6_getaddrinfo(hostname.Value(), NULL, ai); if (res) { dprintf(D_HOSTNAME, "ipv6_getaddrinfo() could not look up %s: %s (%d)\n", hostname.Value(), gai_strerror(res), res); return 0; } while (addrinfo* info = ai.next()) { if (info->ai_canonname) { fqdn = info->ai_canonname; addr = condor_sockaddr(info->ai_addr); return 1; } } hostent* h = gethostbyname(hostname.Value()); if (h && h->h_name && strchr(h->h_name, '.')) { fqdn = h->h_name; addr = condor_sockaddr((sockaddr*)h->h_addr); return 1; } if (h && h->h_aliases && *h->h_aliases) { for (char** alias = h->h_aliases; *alias; ++alias) { if (strchr(*alias, '.')) { fqdn = *alias; addr = condor_sockaddr((sockaddr*)h->h_addr); return 1; } } } } MyString default_domain; // if FQDN is still unresolved, try DEFAULT_DOMAIN_NAME if (ret.Length() == 0 && param(default_domain, "DEFAULT_DOMAIN_NAME")) { ret = hostname; if (ret[ret.Length() - 1] != '.') ret += "."; ret += default_domain; } if (ret.Length() > 0 && found_ip) { fqdn = ret; addr = ret_addr; return 1; } return 0; }
// This is obsolete function. do not use. struct hostent * condor_gethostbyname_ipv6(const char* name) { #define MAXADDR 16 static struct hostent hostent; static struct in_addr addr_list[MAXADDR]; static char *h_addr_list[MAXADDR+1]; static char h_name[NI_MAXHOST]; struct addrinfo hints; struct addrinfo* res = NULL; struct addrinfo* iter; struct hostent* hostent_alias = NULL; int e; int addrcount = 0; int first = 1; if (nodns_enabled()) { return get_nodns_hostent(name); } memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; #ifdef WIN32 // AI_ADDRCONFIG is supported since Windows Server 2008 SDK. hints.ai_flags = AI_CANONNAME; #else hints.ai_flags = AI_ADDRCONFIG | AI_CANONNAME; #endif e = getaddrinfo(name, NULL, &hints, &res); if (e != 0) return NULL; memset(h_addr_list, 0, sizeof(h_addr_list)); memset(h_name, 0, sizeof(h_name)); memset(&hostent, 0, sizeof(hostent)); hostent.h_name = h_name; // fill up h_aliases field by calling gethostbyname(). // it seems there is no way to get DNS aliases from IPv6 functions. // **YOU SHOULD NOT CALL gethostbyname() inside this fn after this point** hostent_alias = gethostbyname(name); if (hostent_alias) { hostent.h_aliases = hostent_alias->h_aliases; } hostent.h_addrtype = AF_INET; hostent.h_length = sizeof(struct in_addr); hostent.h_addr_list = &h_addr_list[0]; for ( iter = res; iter != NULL; iter = iter->ai_next ) { if (first) { // first canonical name is primary name for the host. // rest is aliases if ( iter->ai_canonname ) { strncpy(h_name, iter->ai_canonname, sizeof(h_name)-1); first = 0; } } // pick only IPv4 address if (iter->ai_addr && iter->ai_addr->sa_family == AF_INET) { struct sockaddr_in* _sin = (struct sockaddr_in*)iter->ai_addr; memcpy(&addr_list[addrcount], &_sin->sin_addr, sizeof(struct in_addr)); h_addr_list[addrcount] = (char*)&addr_list[addrcount]; addrcount++; if (addrcount == MAXADDR) break; } } h_addr_list[addrcount] = NULL; freeaddrinfo(res); return &hostent; }
int condor_gethostname(char *name, size_t namelen) { if (nodns_enabled()) { char tmp[MAXHOSTNAMELEN]; char *param_buf; // First, we try NETWORK_INTERFACE if ( (param_buf = param( "NETWORK_INTERFACE" )) ) { char ip_str[MAXHOSTNAMELEN]; // reimplement with condor_sockaddr and to_ip_string() condor_sockaddr addr; dprintf( D_HOSTNAME, "NO_DNS: Using NETWORK_INTERFACE='%s' " "to determine hostname\n", param_buf ); snprintf( ip_str, MAXHOSTNAMELEN, "%s", param_buf ); free( param_buf ); if (!addr.from_ip_string(ip_str)) { dprintf(D_HOSTNAME, "NO_DNS: NETWORK_INTERFACE is invalid: %s\n", ip_str); return -1; } MyString hostname = convert_ipaddr_to_hostname(addr); if (hostname.Length() >= (int) namelen) { return -1; } strcpy(name, hostname.Value()); return 0; } // Second, we try COLLECTOR_HOST // To get the hostname with NODNS we are going to jump // through some hoops. We will try to make a UDP // connection to the COLLECTOR_HOST. This will result in not // only letting us call getsockname to find an IP for this // machine, but it will select the proper IP that we can // use to contact the COLLECTOR_HOST if ( (param_buf = param( "COLLECTOR_HOST" )) ) { //struct hostent *collector_ent; int s; //SOCKET_LENGTH_TYPE addr_len; char collector_host[MAXHOSTNAMELEN]; char *idx; //struct sockaddr_in addr, collector_addr; condor_sockaddr collector_addr; condor_sockaddr addr; std::vector<condor_sockaddr> collector_addrs; dprintf( D_HOSTNAME, "NO_DNS: Using COLLECTOR_HOST='%s' " "to determine hostname\n", param_buf ); // Get only the name portion of the COLLECTOR_HOST if ((idx = index(param_buf, ':'))) { *idx = '\0'; } snprintf( collector_host, MAXHOSTNAMELEN, "%s", param_buf ); free( param_buf ); // Now that we have the name we need an IP collector_addrs = resolve_hostname(collector_host); if (collector_addrs.empty()) { dprintf(D_HOSTNAME, "NO_DNS: Failed to get IP address of collector " "host '%s'\n", collector_host); return -1; } collector_addr = collector_addrs.front(); collector_addr.set_port(1980); // We are doing UDP, the benefit is connect will not send // any network traffic on a UDP socket if (-1 == (s = socket(collector_addr.get_aftype(), SOCK_DGRAM, 0))) { dprintf(D_HOSTNAME, "NO_DNS: Failed to create socket, errno=%d (%s)\n", errno, strerror(errno)); return -1; } if (condor_connect(s, collector_addr)) { perror("connect"); dprintf(D_HOSTNAME, "NO_DNS: Failed to bind socket, errno=%d (%s)\n", errno, strerror(errno)); return -1; } if (condor_getsockname(s, addr)) { dprintf(D_HOSTNAME, "NO_DNS: Failed to get socket name, errno=%d (%s)\n", errno, strerror(errno)); return -1; } MyString hostname = convert_ipaddr_to_hostname(addr); if (hostname.Length() >= (int) namelen) { return -1; } strcpy(name, hostname.Value()); return 0; } // Last, we try gethostname() if ( gethostname( tmp, MAXHOSTNAMELEN ) == 0 ) { dprintf( D_HOSTNAME, "NO_DNS: Using gethostname()='%s' " "to determine hostname\n", tmp ); std::vector<condor_sockaddr> addrs; MyString my_hostname(tmp); addrs = resolve_hostname_raw(my_hostname); if (addrs.empty()) { dprintf(D_HOSTNAME, "NO_DNS: resolve_hostname_raw() failed, errno=%d" " (%s)\n", errno, strerror(errno)); return -1; } MyString hostname = convert_ipaddr_to_hostname(addrs.front()); if (hostname.Length() >= (int) namelen) { return -1; } strcpy(name, hostname.Value()); return 0; } dprintf(D_HOSTNAME, "Failed in determining hostname for this machine\n"); return -1; } else { return gethostname(name, namelen); } }
void init_local_hostname() { // [m.] // initializing local hostname, ip address, fqdn was // super complex. // // implementation was scattered over condor_netdb and // my_hostname, get_full_hostname. // // above them has duplicated code in many ways. // so I aggregated all of them into here. bool ipaddr_inited = false; char hostname[MAXHOSTNAMELEN]; int ret; // [TODO:IPV6] condor_gethostname is not IPv6 safe. // reimplement it. ret = condor_gethostname(hostname, sizeof(hostname)); if (ret) { dprintf(D_ALWAYS, "condor_gethostname() failed. Cannot initialize " "local hostname, ip address, FQDN.\n"); return; } dprintf(D_HOSTNAME, "condor_gethostname() claims we are %s\n", hostname); // Fallback case. local_hostname = hostname; // if NETWORK_INTERFACE is defined, we use that as a local ip addr. MyString network_interface; if (param(network_interface, "NETWORK_INTERFACE", "*")) { if (local_ipaddr.from_ip_string(network_interface)) ipaddr_inited = true; } // Dig around for an IP address in the interfaces // TODO WARNING: Will only return IPv4 addresses! if( ! ipaddr_inited ) { std::string ip; if( ! network_interface_to_ip("NETWORK_INTERFACE", network_interface.Value(), ip, NULL)) { dprintf(D_ALWAYS, "Unable to identify IP address from interfaces. None matches NETWORK_INTERFACE=%s. Problems are likely.\n", network_interface.Value()); return; } if ( ! local_ipaddr.from_ip_string(ip)) { // Should not happen; means network_interface_to_ip returned // invalid IP address. ASSERT(FALSE); } ipaddr_inited = true; } // now initialize hostname and fqdn if (nodns_enabled()) { // if nodns is enabled, we can cut some slack. // condor_gethostname() returns a hostname with // DEFAULT_DOMAIN_NAME. Thus, it is always fqdn local_fqdn = hostname; if (!ipaddr_inited) { local_ipaddr = convert_hostname_to_ipaddr(local_hostname); } return; } addrinfo_iterator ai; ret = ipv6_getaddrinfo(hostname, NULL, ai); if (ret) { // write some error message dprintf(D_HOSTNAME, "hostname %s cannot be resolved by getaddrinfo\n", hostname); return; } int local_hostname_desireability = 0; while (addrinfo* info = ai.next()) { const char* name = info->ai_canonname; if (!name) continue; condor_sockaddr addr(info->ai_addr); int desireability = 0; if (addr.is_loopback()) { desireability = 1; } else if(addr.is_private_network()) { desireability = 2; } else { desireability = 3; } dprintf(D_HOSTNAME, "Considering %s (Ranked at %d) as possible local hostname versus %s/%s (%d)\n", name, desireability, local_hostname.Value(), local_fqdn.Value(), local_hostname_desireability); if(desireability < local_hostname_desireability) { continue; } local_hostname_desireability = desireability; if (!ipaddr_inited) local_ipaddr = addr; const char* dotpos = strchr(name, '.'); if (dotpos) { // consider it as a FQDN local_fqdn = name; local_hostname = local_fqdn.Substr(0, dotpos-name-1); } else { local_hostname = name; local_fqdn = local_hostname; MyString default_domain; if (param(default_domain, "DEFAULT_DOMAIN_NAME")) { if (default_domain[0] != '.') local_fqdn += "."; local_fqdn += default_domain; } } } dprintf(D_HOSTNAME, "Identifying myself as: Short:: %s, Long: %s, IP: %s\n", local_hostname.Value(), local_fqdn.Value(), local_ipaddr.to_ip_string().Value()); hostname_initialized = true; }