/* * Minimal 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 #include #include #include /* 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