gethtbyname: Reserve space for mapping IPv4 address to IPv6 address

Currently function return address space size is reserved by the address
family. When Netd does IPv6 prefix synthesis on an IPv4 resource record,
hostent structure has no enough address space for synthesized IPv6 address.
Reserving enough address space for either IPv4 or IPv6 avoids buffer
overflow while doing address family remapping in Netd.

Be aware of that we don't reserve address space for family remapping in
numeric hostname query which returns a fake address from numeric hostname.
The reason is this case doesn't trigger DNS64 synthesis in Netd.

Bug: 78545619
Test: netd_{unit,integration}_test pass
Change-Id: I506026cfa38c107e06440806a3080dd8d52a3bf2
diff --git a/resolv/gethnamaddr.cpp b/resolv/gethnamaddr.cpp
index ac6a525..017d06d 100644
--- a/resolv/gethnamaddr.cpp
+++ b/resolv/gethnamaddr.cpp
@@ -68,6 +68,7 @@
 #include <sys/un.h>
 #include <syslog.h>
 #include <unistd.h>
+#include <functional>
 
 #include "netd_resolv/resolv.h"
 #include "resolv_cache.h"
@@ -135,8 +136,12 @@
 #endif
 static struct hostent* getanswer(const querybuf*, int, const char*, int, res_state, struct hostent*,
                                  char*, size_t, int*);
+static void convert_v4v6_hostent(struct hostent* hp, char** bpp, char* ep,
+                                 std::function<void(struct hostent* hp)> mapping_param,
+                                 std::function<void(char* src, char* dst)> mapping_addr);
 static void map_v4v6_address(const char*, char*);
 static void map_v4v6_hostent(struct hostent*, char**, char*);
+static void pad_v4v6_hostent(struct hostent* hp, char** bpp, char* ep);
 static void addrsort(char**, int, res_state);
 
 struct hostent* ht_gethostbyname(char*);
@@ -450,6 +455,7 @@
             bp += n;
         }
         if (res->options & RES_USE_INET6) map_v4v6_hostent(hent, &bp, ep);
+        if (hent->h_addrtype == AF_INET) pad_v4v6_hostent(hent, &bp, ep);
         goto success;
     }
 no_recovery:
@@ -819,17 +825,16 @@
     memcpy(p, tmp, NS_INADDRSZ);
 }
 
-static void map_v4v6_hostent(struct hostent* hp, char** bpp, char* ep) {
-    char** ap;
-
+static void convert_v4v6_hostent(struct hostent* hp, char** bpp, char* ep,
+                                 std::function<void(struct hostent* hp)> map_param,
+                                 std::function<void(char* src, char* dst)> map_addr) {
     _DIAGASSERT(hp != NULL);
     _DIAGASSERT(bpp != NULL);
     _DIAGASSERT(ep != NULL);
 
     if (hp->h_addrtype != AF_INET || hp->h_length != NS_INADDRSZ) return;
-    hp->h_addrtype = AF_INET6;
-    hp->h_length = NS_IN6ADDRSZ;
-    for (ap = hp->h_addr_list; *ap; ap++) {
+    map_param(hp);
+    for (char** ap = hp->h_addr_list; *ap; ap++) {
         int i = (int) (sizeof(align) - (size_t)((u_long) *bpp % sizeof(align)));
 
         if (ep - *bpp < (i + NS_IN6ADDRSZ)) {
@@ -838,12 +843,33 @@
             return;
         }
         *bpp += i;
-        map_v4v6_address(*ap, *bpp);
+        map_addr(*ap, *bpp);
         *ap = *bpp;
         *bpp += NS_IN6ADDRSZ;
     }
 }
 
+static void map_v4v6_hostent(struct hostent* hp, char** bpp, char* ep) {
+    convert_v4v6_hostent(hp, bpp, ep,
+                         [](struct hostent* hp) {
+                             hp->h_addrtype = AF_INET6;
+                             hp->h_length = NS_IN6ADDRSZ;
+                         },
+                         [](char* src, char* dst) { map_v4v6_address(src, dst); });
+}
+
+/* Reserve space for mapping IPv4 address to IPv6 address in place */
+static void pad_v4v6_hostent(struct hostent* hp, char** bpp, char* ep) {
+    convert_v4v6_hostent(hp, bpp, ep,
+                         [](struct hostent* hp) {
+                             (void) hp; /* unused */
+                         },
+                         [](char* src, char* dst) {
+                             memcpy(dst, src, NS_INADDRSZ);
+                             memcpy(dst + NS_INADDRSZ, NAT64_PAD, sizeof(NAT64_PAD));
+                         });
+}
+
 static void addrsort(char** ap, int num, res_state res) {
     int i, j;
     char** p;
diff --git a/resolv/sethostent.cpp b/resolv/sethostent.cpp
index 4365c03..7c5b905 100644
--- a/resolv/sethostent.cpp
+++ b/resolv/sethostent.cpp
@@ -142,7 +142,14 @@
     HENT_ARRAY(hp->h_aliases, anum, ptr, len);
     HENT_ARRAY(hp->h_addr_list, num, ptr, len);
 
-    for (i = 0; i < num; i++) HENT_COPY(hp->h_addr_list[i], addr_ptrs[i], hp->h_length, ptr, len);
+    for (i = 0; i < num; i++) {
+        HENT_COPY(hp->h_addr_list[i], addr_ptrs[i], hp->h_length, ptr, len);
+
+        // reserve space for mapping IPv4 address to IPv6 address in place
+        if (hp->h_addrtype == AF_INET) {
+            HENT_COPY(ptr, NAT64_PAD, sizeof(NAT64_PAD), ptr, len);
+        }
+    }
     hp->h_addr_list[num] = NULL;
 
     HENT_SCOPY(hp->h_name, hent.h_name, ptr, len);