Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAJeyfuqWWpw5aOPYshPh-RmVCfEa9y_t3rXoDteYZWuwfy11Mw@mail.gmail.com>
Date: Fri, 25 Jul 2025 14:55:24 +0900
From: Yusuke Endoh <mame@...y-lang.org>
To: musl@...ts.openwall.com
Subject: Bug in IN6_IS_ADDR_V4COMPAT macro for addresses ending in .1

Hello,

I believe I've found a bug in the IN6_IS_ADDR_V4COMPAT macro.
It incorrectly returns false for IPv4-compatible addresses
where the last octet is 1, such as ::192.168.1.1. It should return true.

## Reproduction Code

```
#include <stdio.h>
#include <arpa/inet.h>
#include <netinet/in.h>

int test(const char *str) {
    struct in6_addr addr;

    if (inet_pton(AF_INET6, str, &addr) != 1) {
        perror("inet_pton failed");
        return -1;
    }

    return IN6_IS_ADDR_V4COMPAT(&addr);
}

int main() {
    printf("IN6_IS_ADDR_V4COMPAT(::192.168.1.1) = %d\n",
test("::192.168.1.1"));
    printf("IN6_IS_ADDR_V4COMPAT(::192.168.1.2) = %d\n",
test("::192.168.1.2"));

    return 0;
}
```

## Expected Result (with glibc)

```
$ gcc -o test test.c && ./test
IN6_IS_ADDR_V4COMPAT(::192.168.1.1) = 1
IN6_IS_ADDR_V4COMPAT(::192.168.1.2) = 1
```

## Actual Result (with musl-gcc)

```
$ musl-gcc -o test test.c && ./test
IN6_IS_ADDR_V4COMPAT(::192.168.1.1) = 0
IN6_IS_ADDR_V4COMPAT(::192.168.1.2) = 1
```

As you can see, the macro returns false for ::192.168.1.1,
while it correctly returns true for ::192.168.1.2.

## Suggested Fix

I suspect the condition in the macro is incorrect.
Currently it checks if the LSB is "> 1", but it should be ">= 1".

Here is a proposed patch:

```
diff --git a/include/netinet/in.h b/include/netinet/in.h
index fb628b61..71bc26ab 100644
--- a/include/netinet/in.h
+++ b/include/netinet/in.h
@@ -132,7 +132,7 @@ uint16_t ntohs(uint16_t);

 #define IN6_IS_ADDR_V4COMPAT(a) \
         (((uint32_t *) (a))[0] == 0 && ((uint32_t *) (a))[1] == 0 && \
-         ((uint32_t *) (a))[2] == 0 && ((uint8_t *) (a))[15] > 1)
+         ((uint32_t *) (a))[2] == 0 && ((uint8_t *) (a))[15] >= 1)

 #define IN6_IS_ADDR_MC_NODELOCAL(a) \
         (IN6_IS_ADDR_MULTICAST(a) && ((((uint8_t *) (a))[1] & 0xf) == 0x1))
```

Thank you for your time and for maintaining this great project.

Best regards,
Yusuke

Content of type "text/html" skipped

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.