From 0b905b49d460a57773d88d714cd880ffe0182b7c Mon Sep 17 00:00:00 2001 From: Yuri Pankov Date: Fri, 7 Jul 2017 18:55:34 +0300 Subject: [PATCH] 5980 in-kernel inet_ntop should format IPv4 addresses like userland one Reviewed by: Igor Kozhukhov Reviewed by: Dan McDonald Reviewed by: Vitaliy Gusev Approved by: Richard Lowe --- usr/src/common/smbsrv/smb_inet.c | 30 +--- usr/src/uts/common/inet/ip.h | 12 +- usr/src/uts/common/inet/ip/inet_ntop.c | 180 ++++++++++----------- .../common/io/comstar/port/iscsit/iscsit_text.c | 18 +-- usr/src/uts/common/io/idm/idm_so.c | 55 +++---- .../uts/common/io/scsi/adapters/iscsi/persistent.c | 82 +++++----- 6 files changed, 175 insertions(+), 202 deletions(-) diff --git a/usr/src/common/smbsrv/smb_inet.c b/usr/src/common/smbsrv/smb_inet.c index db3a38fa50..023e9986bb 100644 --- a/usr/src/common/smbsrv/smb_inet.c +++ b/usr/src/common/smbsrv/smb_inet.c @@ -18,11 +18,11 @@ * * CDDL HEADER END */ + /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. - * - * Copyright 2014 Nexenta Systems, Inc. All rights reserved. + * Copyright 2017 Nexenta Systems, Inc. */ /* @@ -101,28 +101,12 @@ smb_inet_iszero(smb_inaddr_t *ipaddr) const char * smb_inet_ntop(smb_inaddr_t *addr, char *buf, int size) { - /* Lint avoidance. */ -#if !defined(_KERNEL) - size_t sz = (size_t)size; -#else /* _KERNEL */ + /* Lint avoidance */ +#ifdef _KERNEL int sz = size; - - /* - * Until uts/common/inet/ip/inet_ntop.c is fixed so it - * no longer uses leading zeros printing IPv4 addresses, - * we need to handle IPv4 ourselves. If we leave the - * leading zeros, Windows clients get errors trying to - * resolve those address strings to names. After: - * https://www.illumos.org/issues/5980 is fixed, - * this work-around can be removed. - */ - if (addr->a_family == AF_INET) { - uint8_t *p = (void *) &addr->a_ipv4; - (void) snprintf(buf, size, "%d.%d.%d.%d", - p[0], p[1], p[2], p[3]); - return (buf); - } -#endif /* _KERNEL */ +#else + size_t sz = (size_t)size; +#endif return ((char *)inet_ntop(addr->a_family, addr, buf, sz)); } diff --git a/usr/src/uts/common/inet/ip.h b/usr/src/uts/common/inet/ip.h index f8ebb28ce8..cc8c489c8c 100644 --- a/usr/src/uts/common/inet/ip.h +++ b/usr/src/uts/common/inet/ip.h @@ -23,7 +23,7 @@ * Copyright (c) 1990 Mentat Inc. * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, Joyent, Inc. All rights reserved. - * Copyright 2014 Nexenta Systems, Inc. All rights reserved. + * Copyright 2017 Nexenta Systems, Inc. * Copyright 2017 OmniTI Computer Consulting, Inc. All rights reserved. */ @@ -3713,11 +3713,13 @@ extern boolean_t ip_recv_attr_from_mblk(mblk_t *, ip_recv_attr_t *); extern mblk_t *ip_recv_attr_free_mblk(mblk_t *); extern boolean_t ip_recv_attr_is_mblk(mblk_t *); -#ifdef __PRAGMA_REDEFINE_EXTNAME -#pragma redefine_extname inet_pton _inet_pton -#else /* __PRAGMA_REDEFINE_EXTNAME */ +#ifdef __PRAGMA_REDEFINE_EXTNAME +#pragma redefine_extname inet_ntop _inet_ntop +#pragma redefine_extname inet_pton _inet_pton +#else +#define inet_ntop _inet_ntop #define inet_pton _inet_pton -#endif /* __PRAGMA_REDEFINE_EXTNAME */ +#endif /* __PRAGMA_REDEFINE_EXTNAME */ extern char *inet_ntop(int, const void *, char *, int); extern int inet_pton(int, char *, void *); diff --git a/usr/src/uts/common/inet/ip/inet_ntop.c b/usr/src/uts/common/inet/ip/inet_ntop.c index 544e180c72..efad4fc176 100644 --- a/usr/src/uts/common/inet/ip/inet_ntop.c +++ b/usr/src/uts/common/inet/ip/inet_ntop.c @@ -23,7 +23,7 @@ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. - * Copyright 2014 Nexenta Systems, Inc. All rights reserved. + * Copyright 2017 Nexenta Systems, Inc. */ #include @@ -34,96 +34,7 @@ #include #include -static void convert2ascii(char *, const in6_addr_t *); -static char *strchr_w(const char *, int); -static int str2inet_addr(char *, ipaddr_t *); - /* - * inet_ntop -- Convert an IPv4 or IPv6 address in binary form into - * printable form, and return a pointer to that string. Caller should - * provide a buffer of correct length to store string into. - * Note: this routine is kernel version of inet_ntop. It has similar - * format as inet_ntop() defined in rfc2553. But it does not do - * error handling operations exactly as rfc2553 defines. This function - * is used by kernel inet directory routines only for debugging. - * This inet_ntop() function, does not return NULL if third argument - * is NULL. The reason is simple that we don't want kernel to panic - * as the output of this function is directly fed to ipdbg macro. - * Instead it uses a local buffer for destination address for - * those calls which purposely pass NULL ptr for the destination - * buffer. This function is thread-safe when the caller passes a non- - * null buffer with the third argument. - */ -/* ARGSUSED */ -char * -inet_ntop(int af, const void *addr, char *buf, int addrlen) -{ - static char local_buf[INET6_ADDRSTRLEN]; - static char *err_buf1 = ""; - static char *err_buf2 = ""; - in6_addr_t *v6addr; - uchar_t *v4addr; - char *caddr; - - /* - * We don't allow thread unsafe inet_ntop calls, they - * must pass a non-null buffer pointer. For DEBUG mode - * we use the ASSERT() and for non-debug kernel it will - * silently allow it for now. Someday we should remove - * the static buffer from this function. - */ - - ASSERT(buf != NULL); - if (buf == NULL) - buf = local_buf; - buf[0] = '\0'; - - /* Let user know politely not to send NULL or unaligned addr */ - if (addr == NULL || !(OK_32PTR(addr))) { -#ifdef DEBUG - cmn_err(CE_WARN, "inet_ntop: addr is or unaligned"); -#endif - return (err_buf1); - } - - -#define UC(b) (((int)b) & 0xff) - switch (af) { - case AF_INET: - ASSERT(addrlen >= INET_ADDRSTRLEN); - v4addr = (uchar_t *)addr; - (void) sprintf(buf, "%03d.%03d.%03d.%03d", - UC(v4addr[0]), UC(v4addr[1]), UC(v4addr[2]), UC(v4addr[3])); - return (buf); - - case AF_INET6: - ASSERT(addrlen >= INET6_ADDRSTRLEN); - v6addr = (in6_addr_t *)addr; - if (IN6_IS_ADDR_V4MAPPED(v6addr)) { - caddr = (char *)addr; - (void) sprintf(buf, "::ffff:%d.%d.%d.%d", - UC(caddr[12]), UC(caddr[13]), - UC(caddr[14]), UC(caddr[15])); - } else if (IN6_IS_ADDR_V4COMPAT(v6addr)) { - caddr = (char *)addr; - (void) sprintf(buf, "::%d.%d.%d.%d", - UC(caddr[12]), UC(caddr[13]), UC(caddr[14]), - UC(caddr[15])); - } else if (IN6_IS_ADDR_UNSPECIFIED(v6addr)) { - (void) sprintf(buf, "::"); - } else { - convert2ascii(buf, v6addr); - } - return (buf); - - default: - return (err_buf2); - } -#undef UC -} - -/* - * * v6 formats supported * General format xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx * The short hand notation :: is used for COMPAT addr @@ -256,6 +167,93 @@ str2inet_addr(char *cp, ipaddr_t *addrp) } /* + * inet_ntop: Convert an IPv4 or IPv6 address in binary form into + * printable form, and return a pointer to that string. Caller should + * provide a buffer of correct length to store string into. + * Note: this routine is kernel version of inet_ntop. It has similar + * format as inet_ntop() defined in RFC 2553, but it does not do + * error handling operations exactly as RFC 2553 defines. + */ +static char * +__inet_ntop(int af, const void *addr, char *buf, int addrlen, int compat) +{ + static char *badaf = ""; + in6_addr_t *v6addr; + uchar_t *v4addr; + char *caddr; + + VERIFY(addr != NULL); + VERIFY(OK_32PTR(addr)); + VERIFY(buf != NULL); + + buf[0] = '\0'; + +#define UC(b) (((int)b) & 0xff) + switch (af) { + case AF_INET: + ASSERT(addrlen >= INET_ADDRSTRLEN); + v4addr = (uchar_t *)addr; + (void) sprintf(buf, + (compat) ? "%03d.%03d.%03d.%03d" : "%d.%d.%d.%d", + UC(v4addr[0]), UC(v4addr[1]), UC(v4addr[2]), UC(v4addr[3])); + return (buf); + case AF_INET6: + ASSERT(addrlen >= INET6_ADDRSTRLEN); + v6addr = (in6_addr_t *)addr; + if (IN6_IS_ADDR_V4MAPPED(v6addr)) { + caddr = (char *)addr; + (void) sprintf(buf, "::ffff:%d.%d.%d.%d", + UC(caddr[12]), UC(caddr[13]), + UC(caddr[14]), UC(caddr[15])); + } else if (IN6_IS_ADDR_V4COMPAT(v6addr)) { + caddr = (char *)addr; + (void) sprintf(buf, "::%d.%d.%d.%d", + UC(caddr[12]), UC(caddr[13]), UC(caddr[14]), + UC(caddr[15])); + } else if (IN6_IS_ADDR_UNSPECIFIED(v6addr)) { + (void) sprintf(buf, "::"); + } else { + convert2ascii(buf, v6addr); + } + return (buf); + + default: + return (badaf); + } +#undef UC +} + +/* + * Provide fixed inet_ntop() implementation. + */ +char * +_inet_ntop(int af, const void *addr, char *buf, int addrlen) +{ + return (__inet_ntop(af, addr, buf, addrlen, 0)); +} + +/* + * Provide old inet_ntop() implementation by default for binary + * compatibility. + */ +char * +inet_ntop(int af, const void *addr, char *buf, int addrlen) +{ + static char local_buf[INET6_ADDRSTRLEN]; + static char *badaddr = ""; + + if (addr == NULL || !(OK_32PTR(addr))) + return (badaddr); + + if (buf == NULL) { + buf = local_buf; + addrlen = sizeof (local_buf); + } + + return (__inet_ntop(af, addr, buf, addrlen, 1)); +} + +/* * inet_pton: This function takes string format IPv4 or IPv6 address and * converts it to binary form. The format of this function corresponds to * inet_pton() in the socket library. @@ -265,7 +263,7 @@ str2inet_addr(char *cp, ipaddr_t *addrp) * 1 successful conversion * -1 af is not AF_INET or AF_INET6 */ -int +static int __inet_pton(int af, char *inp, void *outp, int compat) { int i; diff --git a/usr/src/uts/common/io/comstar/port/iscsit/iscsit_text.c b/usr/src/uts/common/io/comstar/port/iscsit/iscsit_text.c index d2943a9f9d..34b3706eea 100644 --- a/usr/src/uts/common/io/comstar/port/iscsit/iscsit_text.c +++ b/usr/src/uts/common/io/comstar/port/iscsit/iscsit_text.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2014 Nexenta Systems, Inc. All rights reserved. + * Copyright 2017 Nexenta Systems, Inc. */ #include @@ -54,19 +54,6 @@ void iscsit_text_cmd_fini(iscsit_conn_t *ict); -/* - * The kernel inet_ntop() function formats ipv4 address fields with - * leading zeros which the win2k initiator interprets as octal. - */ - -static void -iscsit_v4_ntop(struct in_addr *in, char a[], int size) -{ - unsigned char *p = (unsigned char *) in; - - (void) snprintf(a, size, "%d.%d.%d.%d", *p, *(p+1), *(p+2), *(p+3)); -} - static void iscsit_bump_ttt(iscsit_conn_t *ict) { @@ -135,7 +122,8 @@ iscsit_add_portal(struct sockaddr_storage *ss, int tag, nvlist_t *nv_resp) switch (ss->ss_family) { case AF_INET: sin = (struct sockaddr_in *)ss; - iscsit_v4_ntop(&sin->sin_addr, ipaddr, sizeof (ipaddr)); + (void) inet_ntop(AF_INET, &sin->sin_addr, ipaddr, + sizeof (ipaddr)); (void) snprintf(ta_value, sizeof (ta_value), "%s:%d,%d", ipaddr, ntohs(sin->sin_port), tag); break; diff --git a/usr/src/uts/common/io/idm/idm_so.c b/usr/src/uts/common/io/idm/idm_so.c index 0668614664..61fd0df123 100644 --- a/usr/src/uts/common/io/idm/idm_so.c +++ b/usr/src/uts/common/io/idm/idm_so.c @@ -3093,39 +3093,30 @@ idm_sa_ntop(const struct sockaddr_storage *sa, char tmp[INET6_ADDRSTRLEN]; switch (sa->ss_family) { - case AF_INET6: - { - const struct sockaddr_in6 *in6 = - (const struct sockaddr_in6 *) sa; - - if (inet_ntop(in6->sin6_family, - &in6->sin6_addr, tmp, sizeof (tmp)) == NULL) { - goto err; - } - if (strlen(tmp) + sizeof ("[].65535") > size) { - goto err; - } - /* struct sockaddr_storage gets port info from v4 loc */ - (void) snprintf(buf, size, "[%s].%u", tmp, - ntohs(in6->sin6_port)); - return (buf); - } - case AF_INET: - { - const struct sockaddr_in *in = - (const struct sockaddr_in *) sa; - - if (inet_ntop(in->sin_family, &in->sin_addr, - tmp, sizeof (tmp)) == NULL) { - goto err; - } - if (strlen(tmp) + sizeof ("[].65535") > size) { + case AF_INET6: { + const struct sockaddr_in6 *in6 = + (const struct sockaddr_in6 *) sa; + + (void) inet_ntop(in6->sin6_family, &in6->sin6_addr, tmp, + sizeof (tmp)); + if (strlen(tmp) + sizeof ("[].65535") > size) + goto err; + /* struct sockaddr_storage gets port info from v4 loc */ + (void) snprintf(buf, size, "[%s].%u", tmp, + ntohs(in6->sin6_port)); + return (buf); + } + case AF_INET: { + const struct sockaddr_in *in = (const struct sockaddr_in *) sa; + + (void) inet_ntop(in->sin_family, &in->sin_addr, tmp, + sizeof (tmp)); + if (strlen(tmp) + sizeof ("[].65535") > size) goto err; - } - (void) snprintf(buf, size, "[%s].%u", tmp, - ntohs(in->sin_port)); - return (buf); - } + (void) snprintf(buf, size, "[%s].%u", tmp, + ntohs(in->sin_port)); + return (buf); + } default: break; } diff --git a/usr/src/uts/common/io/scsi/adapters/iscsi/persistent.c b/usr/src/uts/common/io/scsi/adapters/iscsi/persistent.c index 50d6516087..9eb40611cd 100644 --- a/usr/src/uts/common/io/scsi/adapters/iscsi/persistent.c +++ b/usr/src/uts/common/io/scsi/adapters/iscsi/persistent.c @@ -70,11 +70,30 @@ static boolean_t persistent_disc_meth_common(iSCSIDiscoveryMethod_t method, static void persistent_static_addr_upgrade_to_v2(); /* + * This wrapper keeps old inet_ntop() behaviour and should be called when + * IP addresses are used as keys into persistent storage. + */ +static void +iscsi_inet_ntop(int af, const void *addr, char *buf) +{ +#define UC(b) (((int)b) & 0xff) + if (af == AF_INET) { + uchar_t *v4addr = (uchar_t *)addr; + (void) snprintf(buf, INET6_ADDRSTRLEN, "%03d.%03d.%03d.%03d", + UC(v4addr[0]), UC(v4addr[1]), UC(v4addr[2]), UC(v4addr[3])); + } else { + (void) inet_ntop(af, addr, buf, INET6_ADDRSTRLEN); + } +#undef UC +} + +/* * persistent_init_disc_addr_oids - Oid is stored with discovery address * however oids are not persisted and the discovery address oids need to * be regenerated during initialization. */ -static void persistent_init_disc_addr_oids() +static void +persistent_init_disc_addr_oids() { uint32_t addr_count = 0; void *void_p = NULL; @@ -122,7 +141,8 @@ static void persistent_init_disc_addr_oids() * however oids are not persisted and the static address oids need to * be regenerated during initialization. */ -static void persistent_init_static_addr_oids() +static void +persistent_init_static_addr_oids() { uint32_t addr_count = 0; void *void_p = NULL; @@ -422,13 +442,10 @@ persistent_static_addr_set(char *target_name, entry_t *e) key = kmem_zalloc(MAX_KEY_SIZE, KM_SLEEP); ip_str = kmem_zalloc(INET6_ADDRSTRLEN, KM_SLEEP); - if (e->e_insize == sizeof (struct in_addr)) { - (void) inet_ntop(AF_INET, &e->e_u.u_in4, - ip_str, INET6_ADDRSTRLEN); - } else { - (void) inet_ntop(AF_INET6, &e->e_u.u_in6, - ip_str, INET6_ADDRSTRLEN); - } + if (e->e_insize == sizeof (struct in_addr)) + iscsi_inet_ntop(AF_INET, &e->e_u.u_in4, ip_str); + else + iscsi_inet_ntop(AF_INET6, &e->e_u.u_in6, ip_str); if (snprintf(key, MAX_KEY_SIZE - 1, "%s,%s:%d,%d", target_name, ip_str, e->e_port, e->e_tpgt) >= MAX_KEY_SIZE) { @@ -517,13 +534,10 @@ persistent_static_addr_clear(uint32_t oid) if (e.e_oid == oid) { ip_str = kmem_zalloc(INET6_ADDRSTRLEN, KM_SLEEP); key = kmem_zalloc(MAX_KEY_SIZE, KM_SLEEP); - if (e.e_insize == sizeof (struct in_addr)) { - (void) inet_ntop(AF_INET, &e.e_u.u_in4, - ip_str, INET6_ADDRSTRLEN); - } else { - (void) inet_ntop(AF_INET6, &e.e_u.u_in6, - ip_str, INET6_ADDRSTRLEN); - } + if (e.e_insize == sizeof (struct in_addr)) + iscsi_inet_ntop(AF_INET, &e.e_u.u_in4, ip_str); + else + iscsi_inet_ntop(AF_INET6, &e.e_u.u_in6, ip_str); if (snprintf(key, MAX_KEY_SIZE - 1, "%s,%s:%d,%d", target_name, ip_str, e.e_port, e.e_tpgt) >= MAX_KEY_SIZE) { @@ -587,11 +601,10 @@ persistent_isns_addr_set(entry_t *e) * nodes do not have an associated node name. A name is manufactured * from the IP address given. */ - if (e->e_insize == sizeof (struct in_addr)) { - (void) inet_ntop(AF_INET, &e->e_u.u_in4, name, sizeof (name)); - } else { - (void) inet_ntop(AF_INET6, &e->e_u.u_in6, name, sizeof (name)); - } + if (e->e_insize == sizeof (struct in_addr)) + iscsi_inet_ntop(AF_INET, &e->e_u.u_in4, name); + else + iscsi_inet_ntop(AF_INET6, &e->e_u.u_in6, name); mutex_enter(&isns_addr_data_lock); rval = nvf_data_set(ISNS_SERVER_ADDR_ID, name, @@ -641,11 +654,10 @@ persistent_isns_addr_clear(entry_t *e) * nodes do not have an associated node name. A name is manufactured * from the IP address given. */ - if (e->e_insize == sizeof (struct in_addr)) { - (void) inet_ntop(AF_INET, &e->e_u.u_in4, name, sizeof (name)); - } else { - (void) inet_ntop(AF_INET6, &e->e_u.u_in6, name, sizeof (name)); - } + if (e->e_insize == sizeof (struct in_addr)) + iscsi_inet_ntop(AF_INET, &e->e_u.u_in4, name); + else + iscsi_inet_ntop(AF_INET6, &e->e_u.u_in6, name); mutex_enter(&static_addr_data_lock); rval = nvf_data_clear(ISNS_SERVER_ADDR_ID, name); @@ -698,11 +710,10 @@ persistent_disc_addr_set(entry_t *e) * nodes do not have an associated node name. A name is manufactured * from the IP address given. */ - if (e->e_insize == sizeof (struct in_addr)) { - (void) inet_ntop(AF_INET, &e->e_u.u_in4, name, sizeof (name)); - } else { - (void) inet_ntop(AF_INET6, &e->e_u.u_in6, name, sizeof (name)); - } + if (e->e_insize == sizeof (struct in_addr)) + iscsi_inet_ntop(AF_INET, &e->e_u.u_in4, name); + else + iscsi_inet_ntop(AF_INET6, &e->e_u.u_in6, name); mutex_enter(&disc_addr_data_lock); rval = nvf_data_set(DISCOVERY_ADDR_ID, name, @@ -752,11 +763,10 @@ persistent_disc_addr_clear(entry_t *e) * nodes do not have an associated node name. A name is manufactured * from the IP address given. */ - if (e->e_insize == sizeof (struct in_addr)) { - (void) inet_ntop(AF_INET, &e->e_u.u_in4, name, sizeof (name)); - } else { - (void) inet_ntop(AF_INET6, &e->e_u.u_in6, name, sizeof (name)); - } + if (e->e_insize == sizeof (struct in_addr)) + iscsi_inet_ntop(AF_INET, &e->e_u.u_in4, name); + else + iscsi_inet_ntop(AF_INET6, &e->e_u.u_in6, name); mutex_enter(&static_addr_data_lock); rval = nvf_data_clear(DISCOVERY_ADDR_ID, name); -- 2.11.4.GIT