net: Fix inet_pton IPv4 implementation

The conversion from IPv4 string presentation to numeric value
did not check if the individual address value was between 0 and 255
inclusive.

Add also test case for this.

Fixes #84593

Signed-off-by: Jukka Rissanen <jukka.rissanen@nordicsemi.no>
This commit is contained in:
Jukka Rissanen 2025-01-27 16:15:44 +02:00 committed by Benjamin Cabé
parent 3e52109590
commit d243bc1fdb
2 changed files with 82 additions and 13 deletions

View File

@ -335,24 +335,63 @@ int z_impl_net_addr_pton(sa_family_t family, const char *src,
{
if (family == AF_INET) {
struct in_addr *addr = (struct in_addr *)dst;
size_t i, len;
len = strlen(src);
for (i = 0; i < len; i++) {
if (!(src[i] >= '0' && src[i] <= '9') &&
src[i] != '.') {
return -EINVAL;
}
}
uint8_t index = 0, digits = 0;
uint16_t value = 0, count = 0;
(void)memset(addr, 0, sizeof(struct in_addr));
for (i = 0; i < sizeof(struct in_addr); i++) {
char *endptr;
/* A valid IPv4 address that can be used with inet_pton
* must be in the standard dotted-decimal notation:
*
* - Four octets, each ranging from 0 to 255
* - Separated by dots (.)
* - No leading zeros in each octet
*/
addr->s4_addr[i] = strtol(src, &endptr, 10);
while (index < sizeof(struct in_addr)) {
if (*src == '\0' || *src == '.') {
if (*src == '.') {
count++;
}
src = ++endptr;
if ((digits > 1 && value < 10) ||
(digits > 2 && value < 100)) {
/* Preceding zeroes */
return -EINVAL;
}
if (digits == 0 || value > UINT8_MAX) {
return -EINVAL;
}
addr->s4_addr[index] = value;
if (*src == '\0') {
break;
}
index++;
digits = 0;
value = 0;
} else if ('0' <= *src && *src <= '9') {
if (++digits > 3) {
/* Number too large */
return -EINVAL;
}
value *= 10;
value += *src - '0';
} else {
/* Invalid character */
return -EINVAL;
}
src++;
}
if (count != 3) {
/* Three dots needed */
return -EINVAL;
}
} else if (family == AF_INET6) {

View File

@ -51,6 +51,36 @@ ZTEST_USER(socket_misc_test_suite, test_inet_pton)
res = zsock_inet_pton(AF_INET6, "a:b:c:d:0:1:2:3z", buf);
zassert_equal(res, 0, "");
res = zsock_inet_pton(AF_INET, "192.0.2.400", buf);
zassert_equal(res, 0, "");
res = zsock_inet_pton(AF_INET, "0.0", buf);
zassert_equal(res, 0, "");
res = zsock_inet_pton(AF_INET, "0.1", buf);
zassert_equal(res, 0, "");
res = zsock_inet_pton(AF_INET, "0", buf);
zassert_equal(res, 0, "");
res = zsock_inet_pton(AF_INET, "1", buf);
zassert_equal(res, 0, "");
res = zsock_inet_pton(AF_INET, "256", buf);
zassert_equal(res, 0, "");
res = zsock_inet_pton(AF_INET, "00.0.0.0", buf);
zassert_equal(res, 0, "");
res = zsock_inet_pton(AF_INET, "0.0.0.0", buf);
zassert_equal(res, 1, "");
res = zsock_inet_pton(AF_INET, "0.0..0", buf);
zassert_equal(res, 0, "");
res = zsock_inet_pton(AF_INET, "1.2.3.0.", buf);
zassert_equal(res, 0, "");
}
#define TEST_MY_IPV4_ADDR "192.0.1.1"