Files
mtkports/www-client/netsurf/compat/arpa/inet.h
T

211 lines
4.6 KiB
C

/*
* Minimal <arpa/inet.h> for the MontaukOS NetSurf port.
*
* NetSurf uses inet_pton() only to recognise IP literals in URLs
* (content/urldb.c, utils/utils.c) -- it never opens a socket with the result.
* A self-contained parser is therefore enough, and keeps this out of the
* MontaukOS libc, where a partial implementation would be misleading.
*
* static inline throughout: these headers are included by a handful of
* translation units and NetSurf builds with -Werror, so a non-static
* definition would either collide at link time or warn when unused.
*/
#ifndef _MONTAUK_COMPAT_ARPA_INET_H_
#define _MONTAUK_COMPAT_ARPA_INET_H_
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdint.h>
#include <string.h>
/* Parse a dotted-quad into 4 network-order bytes. Returns 1 on success. */
static inline int montauk_inet_pton4(const char *src, uint8_t *dst)
{
uint32_t octet = 0;
int digits = 0;
int seen = 0;
uint8_t out[4];
for (;;) {
char c = *src++;
if (c >= '0' && c <= '9') {
if (digits == 3)
return 0;
/* a leading zero is not accepted (023 is ambiguous) */
if (digits == 1 && out[seen] == 0)
return 0;
octet = octet * 10 + (uint32_t)(c - '0');
if (octet > 255)
return 0;
out[seen] = (uint8_t)octet;
digits++;
} else if (c == '.' || c == '\0') {
if (digits == 0)
return 0;
if (c == '\0') {
if (seen != 3)
return 0;
memcpy(dst, out, 4);
return 1;
}
if (seen == 3)
return 0;
seen++;
octet = 0;
digits = 0;
out[seen] = 0;
} else {
return 0;
}
}
}
/*
* Parse an IPv6 literal, including "::" compression and a trailing
* dotted-quad (e.g. ::ffff:192.0.2.1). Returns 1 on success.
*/
static inline int montauk_inet_pton6(const char *src, uint8_t *dst)
{
uint8_t out[16];
int head = 0; /* bytes written before "::" */
int tail = 0; /* bytes buffered after "::" */
uint8_t tailbuf[16];
int seen_compress = 0;
uint8_t *cur = out;
int *curlen = &head;
memset(out, 0, sizeof(out));
if (src[0] == ':') {
if (src[1] != ':')
return 0;
src += 2;
seen_compress = 1;
cur = tailbuf;
curlen = &tail;
if (*src == '\0')
goto done;
}
for (;;) {
uint32_t group = 0;
int digits = 0;
/* a dotted-quad may only appear as the final component */
if (strchr(src, '.') != NULL) {
const char *p = src;
int dots = 0;
while (*p != '\0' && *p != ':') {
if (*p == '.')
dots++;
p++;
}
if (dots == 3 && *p == '\0') {
if (*curlen + 4 > 16)
return 0;
if (montauk_inet_pton4(src, cur + *curlen) == 0)
return 0;
*curlen += 4;
break;
}
}
while (*src != '\0' && *src != ':') {
char c = *src;
uint32_t v;
if (c >= '0' && c <= '9')
v = (uint32_t)(c - '0');
else if (c >= 'a' && c <= 'f')
v = (uint32_t)(c - 'a' + 10);
else if (c >= 'A' && c <= 'F')
v = (uint32_t)(c - 'A' + 10);
else
return 0;
group = group * 16 + v;
if (++digits > 4)
return 0;
src++;
}
if (digits == 0)
return 0;
if (*curlen + 2 > 16)
return 0;
cur[(*curlen)++] = (uint8_t)(group >> 8);
cur[(*curlen)++] = (uint8_t)(group & 0xff);
if (*src == '\0')
break;
src++; /* consume ':' */
if (*src == ':') {
if (seen_compress)
return 0;
seen_compress = 1;
src++;
cur = tailbuf;
curlen = &tail;
if (*src == '\0')
break;
} else if (*src == '\0') {
/* trailing single colon */
return 0;
}
}
done:
if (seen_compress) {
if (head + tail > 15) /* "::" must stand for >= 1 zero group */
return 0;
memmove(out + 16 - tail, tailbuf, (size_t)tail);
memset(out + head, 0, (size_t)(16 - tail - head));
} else if (head != 16) {
return 0;
}
memcpy(dst, out, 16);
return 1;
}
/*
* inet_aton(). Returns non-zero on success, as BSD does.
*
* Only the full dotted-quad form is accepted. Historic inet_aton also takes
* "a", "a.b", "a.b.c" and octal/hex octets, but content/urldb.c immediately
* rejects anything without three dots (see the comment at its call site), so
* the narrower behaviour matches how NetSurf actually uses it -- and refusing
* octal-looking octets like "1.2.3.04" is the safer reading for a URL host.
*/
static inline int inet_aton(const char *cp, struct in_addr *addr)
{
uint8_t out[4];
if (cp == NULL || addr == NULL)
return 0;
if (montauk_inet_pton4(cp, out) != 1)
return 0;
memcpy(&addr->s_addr, out, 4);
return 1;
}
static inline int inet_pton(int af, const char *src, void *dst)
{
if (src == NULL || dst == NULL)
return -1;
if (af == AF_INET)
return montauk_inet_pton4(src, (uint8_t *) dst);
if (af == AF_INET6)
return montauk_inet_pton6(src, (uint8_t *) dst);
return -1; /* EAFNOSUPPORT */
}
#endif