mirror of
https://github.com/curl/curl.git
synced 2026-07-10 08:37:21 +03:00
Also repurpose existing build-time feature checks into unit test 1961,
to verify.
Prior to this patch these functions were auto-detected with both
autotools and cmake. In case of autotools there was an extra
verification phase ensuring the functions work as expected. This step
required running the function, thus was limited to non-cross-builds. For
cross-builds and CMake it always used the system implementation if
present. On Windows it always used the local implementation, because
availability/use is complicated there.
After this patch all platforms, always use the local implementation,
which is known to be accurate. This makes curl behave more consistently,
and simplifies the build process, a fixes cross-builds and CMake
auto-detection differences.
Also:
- test1960: enable unconditionally.
- checksrc: disallow globally, allowlist in `block_ip.c` example.
- dnsd: verify ntop result for NULL before passing to printf.
Ref: https://github.com/curl/curl/pull/22137#issuecomment-4797440983
Ref: #22137
Ref: 8537a5b0bc #16577
Closes #22170
219 lines
6 KiB
C
219 lines
6 KiB
C
/*
|
|
* Copyright (C) 1996-2022 Internet Software Consortium.
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
|
|
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
|
|
* INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
|
|
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
|
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
|
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*
|
|
* SPDX-License-Identifier: ISC
|
|
*/
|
|
#include "curl_setup.h"
|
|
|
|
#ifdef HAVE_SYS_PARAM_H
|
|
#include <sys/param.h>
|
|
#endif
|
|
#ifdef HAVE_NETINET_IN_H
|
|
#include <netinet/in.h>
|
|
#endif
|
|
#ifdef HAVE_ARPA_INET_H
|
|
#include <arpa/inet.h>
|
|
#endif
|
|
|
|
#include "curlx/inet_ntop.h"
|
|
#include "curlx/snprintf.h"
|
|
#include "curlx/strcopy.h"
|
|
|
|
#define IN6ADDRSZ 16
|
|
/* #define INADDRSZ 4 */
|
|
#define INT16SZ 2
|
|
|
|
/*
|
|
* If USE_IPV6 is disabled, we still want to parse IPv6 addresses, so make
|
|
* sure we have _some_ value for AF_INET6 without polluting our fake value
|
|
* everywhere.
|
|
*/
|
|
#if !defined(USE_IPV6) && !defined(AF_INET6)
|
|
#define AF_INET6 (AF_INET + 1)
|
|
#endif
|
|
|
|
/*
|
|
* Format an IPv4 address, more or less like inet_ntop().
|
|
*
|
|
* Returns `dst' (as a const)
|
|
* Note:
|
|
* - uses no static variables
|
|
* - takes an unsigned char* not an in_addr as input
|
|
*/
|
|
static char *inet_ntop4(const unsigned char *src, char *dst, size_t size)
|
|
{
|
|
char tmp[sizeof("255.255.255.255")];
|
|
size_t len;
|
|
|
|
DEBUGASSERT(size >= 16);
|
|
|
|
/* this snprintf() does not overflow the buffer. */
|
|
SNPRINTF(tmp, sizeof(tmp), "%d.%d.%d.%d",
|
|
((int)((unsigned char)src[0])) & 0xff,
|
|
((int)((unsigned char)src[1])) & 0xff,
|
|
((int)((unsigned char)src[2])) & 0xff,
|
|
((int)((unsigned char)src[3])) & 0xff);
|
|
|
|
len = strlen(tmp);
|
|
if(len == 0 || len >= size) {
|
|
#ifdef USE_WINSOCK
|
|
errno = WSAEINVAL;
|
|
#else
|
|
errno = ENOSPC;
|
|
#endif
|
|
return NULL;
|
|
}
|
|
curlx_strcopy(dst, size, tmp, len);
|
|
return dst;
|
|
}
|
|
|
|
/*
|
|
* Convert IPv6 binary address into presentation (printable) format.
|
|
*/
|
|
static char *inet_ntop6(const unsigned char *src, char *dst, size_t size)
|
|
{
|
|
/*
|
|
* Note that int32_t and int16_t need only be "at least" large enough
|
|
* to contain a value of the specified size. On some systems, like
|
|
* Crays, there is no such thing as an integer variable with 16 bits.
|
|
* Keep this in mind if you think this function should have been coded
|
|
* to use pointer overlays. All the world's not a VAX.
|
|
*/
|
|
char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
|
|
char *tp;
|
|
struct {
|
|
int base;
|
|
int len;
|
|
} best, cur;
|
|
unsigned int words[IN6ADDRSZ / INT16SZ];
|
|
int i;
|
|
|
|
/* Preprocess:
|
|
* Copy the input (bytewise) array into a wordwise array.
|
|
* Find the longest run of 0x00's in src[] for :: shorthanding.
|
|
*/
|
|
memset(words, '\0', sizeof(words));
|
|
for(i = 0; i < IN6ADDRSZ; i++)
|
|
words[i / 2] |= ((unsigned int)src[i] << ((1 - (i % 2)) << 3));
|
|
|
|
best.base = -1;
|
|
cur.base = -1;
|
|
best.len = 0;
|
|
cur.len = 0;
|
|
|
|
for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
|
|
if(words[i] == 0) {
|
|
if(cur.base == -1) {
|
|
cur.base = i;
|
|
cur.len = 1;
|
|
}
|
|
else
|
|
cur.len++;
|
|
}
|
|
else if(cur.base != -1) {
|
|
if(best.base == -1 || cur.len > best.len)
|
|
best = cur;
|
|
cur.base = -1;
|
|
}
|
|
}
|
|
if((cur.base != -1) && (best.base == -1 || cur.len > best.len))
|
|
best = cur;
|
|
if(best.base != -1 && best.len < 2)
|
|
best.base = -1;
|
|
/* Format the result. */
|
|
tp = tmp;
|
|
for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
|
|
/* Are we inside the best run of 0x00's? */
|
|
if(best.base != -1 && i >= best.base && i < (best.base + best.len)) {
|
|
if(i == best.base)
|
|
*tp++ = ':';
|
|
continue;
|
|
}
|
|
|
|
/* Are we following an initial run of 0x00s or any real hex?
|
|
*/
|
|
if(i)
|
|
*tp++ = ':';
|
|
|
|
/* Is this address an encapsulated IPv4?
|
|
*/
|
|
if(i == 6 && best.base == 0 &&
|
|
(best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
|
|
if(!inet_ntop4(src + 12, tp, sizeof(tmp) - (tp - tmp))) {
|
|
return NULL;
|
|
}
|
|
tp += strlen(tp);
|
|
break;
|
|
}
|
|
else {
|
|
/* Lower-case digits. Cannot use the set from mprintf.c since this
|
|
needs to work as a curlx function */
|
|
static const unsigned char ldigits[] = "0123456789abcdef";
|
|
|
|
unsigned int w = words[i];
|
|
/* output lowercase 16-bit hex number but ignore leading zeroes */
|
|
if(w & 0xf000)
|
|
*tp++ = ldigits[(w & 0xf000) >> 12];
|
|
if(w & 0xff00)
|
|
*tp++ = ldigits[(w & 0x0f00) >> 8];
|
|
if(w & 0xfff0)
|
|
*tp++ = ldigits[(w & 0x00f0) >> 4];
|
|
*tp++ = ldigits[(w & 0x000f)];
|
|
}
|
|
}
|
|
|
|
/* Was it a trailing run of 0x00's?
|
|
*/
|
|
if(best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ))
|
|
*tp++ = ':';
|
|
|
|
/* Check for overflow, copy, and we are done. */
|
|
if((size_t)(tp - tmp) >= size) {
|
|
#ifdef USE_WINSOCK
|
|
errno = WSAEINVAL;
|
|
#else
|
|
errno = ENOSPC;
|
|
#endif
|
|
return NULL;
|
|
}
|
|
|
|
curlx_strcopy(dst, size, tmp, tp - tmp);
|
|
return dst;
|
|
}
|
|
|
|
/*
|
|
* Convert a network format address to presentation format.
|
|
*
|
|
* Returns pointer to presentation format address (`buf').
|
|
* Returns NULL on error and errno set with the specific
|
|
* error, EAFNOSUPPORT or ENOSPC.
|
|
*
|
|
* On Windows we store the error in the thread errno, not in the Winsock error
|
|
* code. This is to avoid losing the actual last Winsock error. When this
|
|
* function returns NULL, check errno not SOCKERRNO.
|
|
*/
|
|
char *curlx_inet_ntop(int af, const void *src, char *buf, size_t size)
|
|
{
|
|
switch(af) {
|
|
case AF_INET:
|
|
return inet_ntop4((const unsigned char *)src, buf, size);
|
|
case AF_INET6:
|
|
return inet_ntop6((const unsigned char *)src, buf, size);
|
|
default:
|
|
errno = SOCKEAFNOSUPPORT;
|
|
return NULL;
|
|
}
|
|
}
|