curl/lib/curlx/inet_ntop.c
Viktor Szakats 0260e8465a
GHA/checksrc: expand spellcheck, fix issues found
- codespell: break logic out into its own runnable script. Allowing
  to run it on local machines.
- codespell: install via `pip`, bump to latest version.
- codespell: show version number in CI log.
- codespell: drop no longer needed word exception: `msdos`.
- codespell: include all curl source tree, except `packages` and
  `winbuild`. Drop an obsolete file exclusion.
- add new spellchecker job using the `typos` tool. It includes
  the codespell dictionary and a couple more. Use linuxbrew to install
  it. This takes 10 seconds, while installing via `cargo` from source
  would take over a minute.
- codespell: introduce an inline ignore filter compatible with `cspell`
  Make `typos` recognize it, too. Move single exceptions inline.

Fix new typos found. Also rename variables and words to keep
spellchecking exceptions at minumum. This involves touching some tests.
Also switch base64 strings to `%b64[]` to avoid false positives.

Ref: https://github.com/crate-ci/typos/blob/master/docs/reference.md
Ref: https://github.com/codespell-project/codespell?tab=readme-ov-file#inline-ignore
Ref: https://github.com/codespell-project/codespell/issues/1212#issuecomment-1721152455
Ref: https://cspell.org/docs/Configuration/document-settings

Closes #17905
2025-07-21 16:09:01 +02:00

225 lines
6.2 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
*/
/*
* Original code by Paul Vixie. "curlified" by Gisle Vanem.
*/
#include "../curl_setup.h"
#ifndef HAVE_INET_NTOP
#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 "inet_ntop.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 sprintf() does not overflow the buffer. Avoids snprintf to work more
widely. Avoids the msnprintf family to work as a curlx function. */
(void)(sprintf)(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
CURL_SETERRNO(WSAEINVAL);
#else
CURL_SETERRNO(ENOSPC);
#endif
return NULL;
}
strcpy(dst, tmp);
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. Can't 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 16bit 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++ = ':';
*tp++ = '\0';
/* Check for overflow, copy, and we are done.
*/
if((size_t)(tp - tmp) > size) {
#ifdef USE_WINSOCK
CURL_SETERRNO(WSAEINVAL);
#else
CURL_SETERRNO(ENOSPC);
#endif
return NULL;
}
strcpy(dst, 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:
CURL_SETERRNO(SOCKEAFNOSUPPORT);
return NULL;
}
}
#endif /* HAVE_INET_NTOP */