From de82fd88a7e9300f9558f1d30fe1ed744be11aa2 Mon Sep 17 00:00:00 2001 From: Jian Yu Date: Tue, 17 Oct 2023 11:06:39 -0700 Subject: [PATCH] LU-17186 utils: replace gethostby*() with get*info() This patch replaces the deprecated gethostbyname() and gethostbyaddr() functions with getaddrinfo() and getnameinfo() functions respectively. The getaddrinfo() function combines the functionality provided by the gethostbyname() and getservbyname() functions into a single interface, but unlike the latter functions, getaddrinfo() is reentrant and allows programs to eliminate IPv4-versus-IPv6 dependencies. The getnameinfo() function is the inverse of getaddrinfo(): it converts a socket address to a corresponding host and service, in a protocol-independent manner. It combines the functionality of gethostbyaddr() and getservbyport(), but unlike those functions, getnameinfo() is reentrant and allows programs to eliminate IPv4-versus-IPv6 dependencies. Test-Parameters: kerberos=true testlist=sanity-krb5 Test-Parameters: testgroup=review-dne-selinux-ssk-part-2 Signed-off-by: Jian Yu Signed-off-by: Sebastien Buisson Change-Id: Iacb5583826cd2f7329455bc6cbb4477f9087f15a Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/52632 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Andreas Dilger Reviewed-by: James Simmons Reviewed-by: Oleg Drokin --- libcfs/autoconf/lustre-libcfs.m4 | 2 - libcfs/libcfs/util/nidstrings.c | 61 ++++++++++-------- lnet/autoconf/lustre-lnet.m4 | 1 - lustre/autoconf/lustre-core.m4 | 1 - lustre/utils/gss/lgss_krb5_utils.c | 15 ++--- lustre/utils/gss/lsupport.c | 126 +++++++++++++++++++++++++++++++------ lustre/utils/gss/lsupport.h | 1 + lustre/utils/nidlist.c | 5 +- lustre/utils/portals.c | 107 ++++++++++++++++--------------- 9 files changed, 210 insertions(+), 109 deletions(-) diff --git a/libcfs/autoconf/lustre-libcfs.m4 b/libcfs/autoconf/lustre-libcfs.m4 index ac6db4a..85b4f66 100644 --- a/libcfs/autoconf/lustre-libcfs.m4 +++ b/libcfs/autoconf/lustre-libcfs.m4 @@ -2700,8 +2700,6 @@ AC_MSG_NOTICE([LibCFS core checks # libcfs/libcfs/util/nidstrings.c AC_CHECK_HEADERS([netdb.h asm/types.h endian.h]) -AC_CHECK_FUNCS([gethostbyname]) -AC_CHECK_FUNCS([getaddrinfo]) # -------- Check for required packages -------------- diff --git a/libcfs/libcfs/util/nidstrings.c b/libcfs/libcfs/util/nidstrings.c index 636fa36..c35d30d 100644 --- a/libcfs/libcfs/util/nidstrings.c +++ b/libcfs/libcfs/util/nidstrings.c @@ -119,52 +119,60 @@ libcfs_ip_addr2str_size(const __be32 *addr, size_t asize, * sscanf may return immediately if it sees the terminating '0' in a string, so * I initialise the %n variable to the expected length. If sscanf sets it; * fine, if it doesn't, then the scan ended at the end of the string, which is - * fine too :) */ + * fine too :) + */ static int libcfs_ip_str2addr(const char *str, int nob, __u32 *addr) { - unsigned int a; - unsigned int b; - unsigned int c; - unsigned int d; - int n = nob; /* XscanfX */ + unsigned int a, b, c, d; + int n = nob; + int rc = 0; /* numeric IP? */ if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 && n == nob && (a & ~0xff) == 0 && (b & ~0xff) == 0 && (c & ~0xff) == 0 && (d & ~0xff) == 0) { - *addr = ((a<<24)|(b<<16)|(c<<8)|d); + *addr = ((a << 24) | (b << 16) | (c << 8) | d); return 1; } -#ifdef HAVE_GETHOSTBYNAME /* known hostname? */ if (('a' <= str[0] && str[0] <= 'z') || ('A' <= str[0] && str[0] <= 'Z')) { - char *tmp; - - tmp = calloc(1, nob + 1); - if (tmp != NULL) { - struct hostent *he; + char *tmp = NULL; + struct addrinfo hints; + struct addrinfo *ai = NULL; + struct addrinfo *aip = NULL; - memcpy(tmp, str, nob); - tmp[nob] = 0; + tmp = (char *)alloca(nob + 1); + memcpy(tmp, str, nob); + tmp[nob] = 0; - he = gethostbyname(tmp); + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_INET; - free(tmp); + if (getaddrinfo(tmp, NULL, &hints, &ai) != 0) { + rc = 0; + goto out; + } - if (he != NULL) { - __u32 ip = *(__u32 *)he->h_addr; + for (aip = ai; aip; aip = aip->ai_next) { + if (aip->ai_addr) { + struct sockaddr_in *sin = (void *)ai->ai_addr; + __u32 ip = (__u32)sin->sin_addr.s_addr; *addr = ntohl(ip); - return 1; + + rc = 1; + break; } } + + freeaddrinfo(ai); } -#endif - return 0; +out: + return rc; } static int @@ -201,13 +209,17 @@ libcfs_ip_str2addr_size(const char *str, int nob, *alen = 16; goto out; } -#ifdef HAVE_GETADDRINFO + /* known hostname? */ if (('a' <= str[0] && str[0] <= 'z') || ('A' <= str[0] && str[0] <= 'Z')) { struct addrinfo *ai = NULL; + struct addrinfo hints; - if (getaddrinfo(tmp, NULL, NULL, &ai) == 0) { + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_INET; + + if (getaddrinfo(tmp, NULL, &hints, &ai) == 0) { struct addrinfo *a; /* First look for an AF_INET address */ for (a = ai; a; a = a->ai_next) { @@ -236,7 +248,6 @@ libcfs_ip_str2addr_size(const char *str, int nob, } freeaddrinfo(ai); } -#endif out: free(tmp); return *alen != 0; diff --git a/lnet/autoconf/lustre-lnet.m4 b/lnet/autoconf/lustre-lnet.m4 index ef49c89..094acf8 100644 --- a/lnet/autoconf/lustre-lnet.m4 +++ b/lnet/autoconf/lustre-lnet.m4 @@ -1309,7 +1309,6 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([ # lnet/utils/portals.c AC_CHECK_HEADERS([netdb.h]) -AC_CHECK_FUNCS([gethostbyname]) # lnet/utils/wirecheck.c AC_CHECK_FUNCS([strnlen]) diff --git a/lustre/autoconf/lustre-core.m4 b/lustre/autoconf/lustre-core.m4 index 89c09fb..d68ed94 100644 --- a/lustre/autoconf/lustre-core.m4 +++ b/lustre/autoconf/lustre-core.m4 @@ -4824,7 +4824,6 @@ LC_MDS_MAX_THREADS # lustre/utils/create_iam.c # lustre/utils/libiam.c AC_CHECK_HEADERS([netdb.h endian.h]) -AC_CHECK_FUNCS([gethostbyname]) # lustre/utils/llverfs.c lustre/utils/libmount_utils_ldiskfs.c AC_CHECK_HEADERS([ext2fs/ext2fs.h], [], [ diff --git a/lustre/utils/gss/lgss_krb5_utils.c b/lustre/utils/gss/lgss_krb5_utils.c index ebe09fb..a8ee720 100644 --- a/lustre/utils/gss/lgss_krb5_utils.c +++ b/lustre/utils/gss/lgss_krb5_utils.c @@ -187,10 +187,8 @@ int svc_princ_verify_host(krb5_context ctx, loglevel_t loglevel) { struct utsname utsbuf; - struct hostent *host; const int max_namelen = 512; char namebuf[max_namelen]; - char *h_name; if (krb5_princ_component(ctx, princ, 1) == NULL) { logmsg(loglevel, "service principal has no host part\n"); @@ -204,28 +202,27 @@ int svc_princ_verify_host(krb5_context ctx, self_nid); return -1; } - h_name = namebuf; } else { if (uname(&utsbuf)) { logmsg(loglevel, "get UTS name: %s\n", strerror(errno)); return -1; } - host = gethostbyname(utsbuf.nodename); - if (host == NULL) { - logmsg(loglevel, "failed to get local hostname\n"); + if (getcanonname(utsbuf.nodename, namebuf, max_namelen) != 0) { + logmsg(loglevel, + "failed to get canonical name of %s\n", + utsbuf.nodename); return -1; } - h_name = host->h_name; } if (lgss_krb5_strcasecmp(krb5_princ_component(ctx, princ, 1), - h_name)) { + namebuf)) { logmsg(loglevel, "service principal: hostname %.*s " "doesn't match localhost %s\n", krb5_princ_component(ctx, princ, 1)->length, krb5_princ_component(ctx, princ, 1)->data, - h_name); + namebuf); return -1; } diff --git a/lustre/utils/gss/lsupport.c b/lustre/utils/gss/lsupport.c index 545afa3..6e9b382 100644 --- a/lustre/utils/gss/lsupport.c +++ b/lustre/utils/gss/lsupport.c @@ -163,24 +163,118 @@ char gethostname_ex[PATH_MAX] = GSSD_DEFAULT_GETHOSTNAME_EX; typedef int lnd_nid2hostname_t(char *lnd, uint32_t net, uint32_t addr, char *buf, int buflen); +int getcanonname(const char *host, char *buf, int buflen) +{ + struct addrinfo hints; + struct addrinfo *ai = NULL; + struct addrinfo *aip = NULL; + int err = 0; + int rc = 0; + + if (!host || host[0] == '\0') { + printerr(LL_ERR, + "network address or hostname was not specified\n"); + return -1; + } + + if (!buf) { + printerr(LL_ERR, + "canonical name buffer was not defined\n"); + return -1; + } + + if (buflen <= 0) { + printerr(LL_ERR, + "invalid canonical name buffer length: %d\n", buflen); + return -1; + } + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_INET; + hints.ai_flags = AI_CANONNAME; + + err = getaddrinfo(host, NULL, &hints, &ai); + if (err != 0) { + printerr(LL_ERR, + "failed to get addrinfo for %s: %s\n", + host, gai_strerror(err)); + return -1; + } + + for (aip = ai; aip; aip = aip->ai_next) { + if (aip->ai_canonname && aip->ai_canonname[0] != '\0') + break; + } + + if (!aip) { + printerr(LL_ERR, "failed to get canonical name of %s\n", host); + rc = -1; + goto out; + } + + if (strlen(aip->ai_canonname) >= buflen) { + printerr(LL_ERR, "canonical name is too long: %s\n", + aip->ai_canonname); + rc = -1; + goto out; + } + + strncpy(buf, aip->ai_canonname, buflen); + +out: + if (ai != NULL) + freeaddrinfo(ai); + return rc; +} + +static int getaddrcanonname(const uint32_t addr, char *buf, int buflen) +{ + struct sockaddr_in srcaddr; + int err = 0; + int rc = -1; + + if (!buf) { + printerr(LL_ERR, + "canonical name buffer was not defined\n"); + goto out; + } + + if (buflen <= 0) { + printerr(LL_ERR, + "invalid canonical name buffer length: %d\n", buflen); + goto out; + } + + memset(&srcaddr, 0, sizeof(srcaddr)); + srcaddr.sin_family = AF_INET; + srcaddr.sin_addr.s_addr = (in_addr_t)addr; + + err = getnameinfo((struct sockaddr *)&srcaddr, sizeof(srcaddr), + buf, buflen, NULL, 0, 0); + if (err != 0) { + printerr(LL_ERR, + "failed to get nameinfo for 0x%x: %s\n", + addr, gai_strerror(err)); + goto out; + } + rc = 0; + +out: + return rc; +} + /* FIXME what about IPv6? */ static int ipv4_nid2hostname(char *lnd, uint32_t net, uint32_t addr, char *buf, int buflen) { - struct hostent *ent; - addr = htonl(addr); - ent = gethostbyaddr(&addr, sizeof(addr), AF_INET); - if (!ent) { - printerr(LL_ERR, "%s: can't resolve 0x%x\n", lnd, addr); - return -1; - } - if (strlen(ent->h_name) >= buflen) { - printerr(LL_ERR, "%s: name too long: %s\n", lnd, ent->h_name); + + if (getaddrcanonname(addr, buf, buflen) != 0) { + printerr(LL_ERR, "%s: failed to get canonical name of 0x%x\n", + lnd, addr); return -1; } - strcpy(buf, ent->h_name); printerr(LL_INFO, "%s: net 0x%x, addr 0x%x => %s\n", lnd, net, addr, buf); @@ -192,7 +286,6 @@ int lolnd_nid2hostname(char *lnd, uint32_t net, uint32_t addr, char *buf, int buflen) { struct utsname uts; - struct hostent *ent; if (addr) { printerr(LL_ERR, "%s: addr is 0x%x, we expect 0\n", lnd, addr); @@ -204,19 +297,12 @@ int lolnd_nid2hostname(char *lnd, uint32_t net, uint32_t addr, return -1; } - ent = gethostbyname(uts.nodename); - if (!ent) { - printerr(LL_ERR, "%s: failed obtain canonical name of %s\n", + if (getcanonname(uts.nodename, buf, buflen) != 0) { + printerr(LL_ERR, "%s: failed to obtain canonical name of %s\n", lnd, uts.nodename); return -1; } - if (strlen(ent->h_name) >= buflen) { - printerr(LL_ERR, "%s: name too long: %s\n", lnd, ent->h_name); - return -1; - } - strcpy(buf, ent->h_name); - printerr(LL_DEBUG, "%s: addr 0x%x => %s\n", lnd, addr, buf); return 0; } diff --git a/lustre/utils/gss/lsupport.h b/lustre/utils/gss/lsupport.h index 36b8d67e..6d565f8 100644 --- a/lustre/utils/gss/lsupport.h +++ b/lustre/utils/gss/lsupport.h @@ -104,6 +104,7 @@ struct lgssd_upcall_data { #define GSSD_DEFAULT_GETHOSTNAME_EX "/etc/lustre/nid2hostname" #define MAPPING_DATABASE_FILE "/etc/lustre/idmap.conf" +int getcanonname(const char *host, char *buf, int buflen); int lnet_nid2hostname(lnet_nid_t nid, char *buf, int buflen); void cleanup_mapping(void); uid_t parse_uid(char *uidstr); diff --git a/lustre/utils/nidlist.c b/lustre/utils/nidlist.c index 3af3c30..4ca40d1 100644 --- a/lustre/utils/nidlist.c +++ b/lustre/utils/nidlist.c @@ -198,6 +198,7 @@ static char *nl_nid_lookup_ipaddr(char *nid) struct addrinfo *ai, *aip; char name[NI_MAXHOST] = ""; char *p, *addr, *lnet = NULL, *res = NULL; + struct addrinfo hints; int len, x; addr = nl_nid_addr(nid); @@ -205,7 +206,9 @@ static char *nl_nid_lookup_ipaddr(char *nid) p = strchr(nid, '@'); if (p) lnet = p + 1; - if (getaddrinfo(addr, NULL, NULL, &ai) == 0) { + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_INET; + if (getaddrinfo(addr, NULL, &hints, &ai) == 0) { for (aip = ai; aip != NULL; aip = aip->ai_next) { if (getnameinfo(aip->ai_addr, aip->ai_addrlen, name, sizeof(name), NULL, 0, diff --git a/lustre/utils/portals.c b/lustre/utils/portals.c index 6be4c15..e9ebf3f 100644 --- a/lustre/utils/portals.c +++ b/lustre/utils/portals.c @@ -32,6 +32,9 @@ #include #include #include +#include +#include +#include #include #include @@ -97,31 +100,6 @@ lnet_parse_port(int *port, char *str) return -1; } -#ifdef HAVE_GETHOSTBYNAME -static struct hostent * -ptl_gethostbyname(char *hname) -{ - struct hostent *he; - - he = gethostbyname(hname); - if (!he) { - switch (h_errno) { - case HOST_NOT_FOUND: - case NO_ADDRESS: - fprintf(stderr, "Unable to resolve hostname: %s\n", - hname); - break; - default: - fprintf(stderr, "gethostbyname error for %s: %s\n", - hname, strerror(h_errno)); - break; - } - return NULL; - } - return he; -} -#endif - int lnet_parse_ipquad(__u32 *ipaddrp, char *str) { @@ -141,9 +119,11 @@ lnet_parse_ipquad(__u32 *ipaddrp, char *str) int lnet_parse_ipaddr(__u32 *ipaddrp, char *str) { -#ifdef HAVE_GETHOSTBYNAME - struct hostent *he; -#endif + struct addrinfo *ai = NULL; + struct addrinfo *aip = NULL; + struct addrinfo hints; + int err = 0; + int rc = -1; if (!strcmp(str, "_all_")) { *ipaddrp = 0; @@ -153,40 +133,67 @@ lnet_parse_ipaddr(__u32 *ipaddrp, char *str) if (lnet_parse_ipquad(ipaddrp, str) == 0) return 0; -#ifdef HAVE_GETHOSTBYNAME - if ((('a' <= str[0] && str[0] <= 'z') || - ('A' <= str[0] && str[0] <= 'Z')) && - (he = ptl_gethostbyname(str)) != NULL) { - __u32 addr = *(__u32 *)he->h_addr; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_INET; - *ipaddrp = ntohl(addr); /* HOST byte order */ - return 0; + if (('a' <= str[0] && str[0] <= 'z') || + ('A' <= str[0] && str[0] <= 'Z')) { + err = getaddrinfo(str, NULL, &hints, &ai); + if (err != 0) { + fprintf(stderr, + "failed to get addrinfo for %s: %s\n", + str, gai_strerror(err)); + return -1; + } + + for (aip = ai; aip; aip = aip->ai_next) { + if (aip->ai_family == AF_INET && aip->ai_addr) { + struct sockaddr_in *sin = + (void *)ai->ai_addr; + + __u32 addr = (__u32)sin->sin_addr.s_addr; + *ipaddrp = ntohl(addr); + break; + } + } + /* FIXME: handle AF_INET6 */ + + if (!aip) { + fprintf(stderr, "failed to get IP address for %s\n", + str); + rc = -1; + goto out; + } + + rc = 0; + goto out; } -#endif - return -1; +out: + if (ai != NULL) + freeaddrinfo(ai); + return rc; } char * ptl_ipaddr_2_str(__u32 ipaddr, char *str, size_t strsize, int lookup) { -#ifdef HAVE_GETHOSTBYNAME - __u32 net_ip; - struct hostent *he; + struct sockaddr_in srcaddr; if (lookup) { - net_ip = htonl(ipaddr); - he = gethostbyaddr(&net_ip, sizeof(net_ip), AF_INET); - if (he) { - snprintf(str, strsize, "%s", he->h_name); - return str; - } + memset(&srcaddr, 0, sizeof(srcaddr)); + srcaddr.sin_family = AF_INET; + srcaddr.sin_addr.s_addr = (in_addr_t)htonl(ipaddr); + + if (getnameinfo((struct sockaddr *)&srcaddr, sizeof(srcaddr), + str, strsize, NULL, 0, 0) == 0) + goto out; } -#endif - sprintf(str, "%d.%d.%d.%d", - (ipaddr >> 24) & 0xff, (ipaddr >> 16) & 0xff, - (ipaddr >> 8) & 0xff, ipaddr & 0xff); + snprintf(str, strsize, "%d.%d.%d.%d", + (ipaddr >> 24) & 0xff, (ipaddr >> 16) & 0xff, + (ipaddr >> 8) & 0xff, ipaddr & 0xff); +out: return str; } -- 1.8.3.1