diff --git a/service/native/libs/libclat/clatutils.cpp b/service/native/libs/libclat/clatutils.cpp index 2a53ba8079..69076c5542 100644 --- a/service/native/libs/libclat/clatutils.cpp +++ b/service/native/libs/libclat/clatutils.cpp @@ -14,7 +14,10 @@ #include "libclat/clatutils.h" +#include #include +#include +#include extern "C" { #include "checksum.h" @@ -46,6 +49,43 @@ void makeChecksumNeutral(in6_addr* v6, const in_addr v4, const in6_addr& nat64Pr v6->s6_addr[12] = delta & 0xff; } +// Picks a random interface ID that is checksum neutral with the IPv4 address and the NAT64 prefix. +int generateIpv6Address(const char* iface, const in_addr v4, const in6_addr& nat64Prefix, + in6_addr* v6) { + int s = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0); + if (s == -1) return -errno; + + if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, iface, strlen(iface) + 1) == -1) { + close(s); + return -errno; + } + + sockaddr_in6 sin6 = {.sin6_family = AF_INET6, .sin6_addr = nat64Prefix}; + if (connect(s, reinterpret_cast(&sin6), sizeof(sin6)) == -1) { + close(s); + return -errno; + } + + socklen_t len = sizeof(sin6); + if (getsockname(s, reinterpret_cast(&sin6), &len) == -1) { + close(s); + return -errno; + } + + *v6 = sin6.sin6_addr; + + if (IN6_IS_ADDR_UNSPECIFIED(v6) || IN6_IS_ADDR_LOOPBACK(v6) || IN6_IS_ADDR_LINKLOCAL(v6) || + IN6_IS_ADDR_SITELOCAL(v6) || IN6_IS_ADDR_ULA(v6)) { + close(s); + return -ENETUNREACH; + } + + makeChecksumNeutral(v6, v4, nat64Prefix); + close(s); + + return 0; +} + } // namespace clat } // namespace net } // namespace android diff --git a/service/native/libs/libclat/include/libclat/clatutils.h b/service/native/libs/libclat/include/libclat/clatutils.h index 05c99df66d..b86ee88e20 100644 --- a/service/native/libs/libclat/include/libclat/clatutils.h +++ b/service/native/libs/libclat/include/libclat/clatutils.h @@ -21,6 +21,9 @@ namespace net { namespace clat { void makeChecksumNeutral(in6_addr* v6, const in_addr v4, const in6_addr& nat64Prefix); +int generateIpv6Address(const char* iface, const in_addr v4, const in6_addr& nat64Prefix, + in6_addr* v6); + } // namespace clat } // namespace net } // namespace android