summaryrefslogtreecommitdiff
path: root/otherlibs
diff options
context:
space:
mode:
authorOlivier Nicole <olivier@chnik.fr>2022-08-01 14:08:56 +0200
committerGitHub <noreply@github.com>2022-08-01 14:08:56 +0200
commit4ec8c91d5a8ea245f2ba6e980fb9a16b536a4263 (patch)
tree3d94d47b1f8d92f849ab145cebbe19e42704419c /otherlibs
parent9653e0d6b092b5147aa1a7c4518dd747092e21b8 (diff)
downloadocaml-4ec8c91d5a8ea245f2ba6e980fb9a16b536a4263.tar.gz
Fix gethostbyaddr for IPv6 arguments and make it domain-safe (#11461)
caml_gethostbyaddr would always call gethostbyaddr with an IPv4 address type and structure, even when its argument is an IPv6 address. This commit also removes a file-local mutable variable for the sake of domain safety. Added a test.
Diffstat (limited to 'otherlibs')
-rw-r--r--otherlibs/unix/gethost.c50
1 files changed, 34 insertions, 16 deletions
diff --git a/otherlibs/unix/gethost.c b/otherlibs/unix/gethost.c
index e7fa2c2db7..34480cdc04 100644
--- a/otherlibs/unix/gethost.c
+++ b/otherlibs/unix/gethost.c
@@ -36,22 +36,22 @@
#define GETHOSTBYNAME_IS_REENTRANT 1
#endif
-static int entry_h_length;
-
-static value alloc_one_addr(char const *a)
+static value alloc_one_addr_ipv4(char const *a)
{
struct in_addr addr;
-#ifdef HAS_IPV6
- struct in6_addr addr6;
- if (entry_h_length == 16) {
- memmove(&addr6, a, 16);
- return caml_unix_alloc_inet6_addr(&addr6);
- }
-#endif
memmove (&addr, a, 4);
return caml_unix_alloc_inet_addr(&addr);
}
+#ifdef HAS_IPV6
+static value alloc_one_addr_ipv6(char const *a)
+{
+ struct in6_addr addr6;
+ memmove(&addr6, a, 16);
+ return caml_unix_alloc_inet6_addr(&addr6);
+}
+#endif
+
static value alloc_host_entry(struct hostent *entry)
{
CAMLparam0();
@@ -65,9 +65,10 @@ static value alloc_host_entry(struct hostent *entry)
aliases = caml_copy_string_array((const char**)entry->h_aliases);
else
aliases = Atom(0);
- entry_h_length = entry->h_length;
addr_list =
- caml_alloc_array(alloc_one_addr, (const char**)entry->h_addr_list);
+ caml_alloc_array((entry->h_addrtype == AF_INET6) ?
+ alloc_one_addr_ipv6 : alloc_one_addr_ipv4,
+ (const char**)entry->h_addr_list);
res = caml_alloc_small(4, 0);
Field(res, 0) = name;
Field(res, 1) = aliases;
@@ -82,14 +83,31 @@ static value alloc_host_entry(struct hostent *entry)
CAMLprim value caml_unix_gethostbyaddr(value a)
{
- struct in_addr adr = GET_INET_ADDR(a);
+ char * adr;
+ struct in_addr in4;
struct hostent * hp;
+ int addr_type = AF_INET;
+ socklen_t addr_len = 4;
+#if HAS_IPV6
+ struct in6_addr in6;
+ if (caml_string_length(a) == 16) {
+ addr_type = AF_INET6;
+ addr_len = 16;
+ in6 = GET_INET6_ADDR(a);
+ adr = (char *)&in6;
+ } else {
+#endif
+ in4 = GET_INET_ADDR(a);
+ adr = (char *)&in4;
+#if HAS_IPV6
+ }
+#endif
#if HAS_GETHOSTBYADDR_R == 7
struct hostent h;
char buffer[NETDB_BUFFER_SIZE];
int h_errnop;
caml_enter_blocking_section();
- hp = gethostbyaddr_r((char *) &adr, 4, AF_INET,
+ hp = gethostbyaddr_r(adr, addr_len, addr_type,
&h, buffer, sizeof(buffer), &h_errnop);
caml_leave_blocking_section();
#elif HAS_GETHOSTBYADDR_R == 8
@@ -97,7 +115,7 @@ CAMLprim value caml_unix_gethostbyaddr(value a)
char buffer[NETDB_BUFFER_SIZE];
int h_errnop, rc;
caml_enter_blocking_section();
- rc = gethostbyaddr_r((char *) &adr, 4, AF_INET,
+ rc = gethostbyaddr_r(adr, addr_len, addr_type,
&h, buffer, sizeof(buffer), &hp, &h_errnop);
caml_leave_blocking_section();
if (rc != 0) hp = NULL;
@@ -105,7 +123,7 @@ CAMLprim value caml_unix_gethostbyaddr(value a)
#ifdef GETHOSTBYADDR_IS_REENTRANT
caml_enter_blocking_section();
#endif
- hp = gethostbyaddr((char *) &adr, 4, AF_INET);
+ hp = gethostbyaddr(adr, addr_len, addr_type);
#ifdef GETHOSTBYADDR_IS_REENTRANT
caml_leave_blocking_section();
#endif