diff --git a/src/api/netdb.c b/src/api/netdb.c
index e07ab049..4d0486e2 100644
--- a/src/api/netdb.c
+++ b/src/api/netdb.c
@@ -49,12 +49,11 @@
 #include <string.h> /* memset */
 #include <stdlib.h> /* atoi */
 
-/** helper struct for gethostbyname_r to access the char* buffer */
-struct gethostbyname_r_helper {
-  ip_addr_t *addr_list[2];
-  ip_addr_t addr;
-  char *aliases;
-};
+#if LWIP_IPV6
+#define HOSTENT_BUFLEN LWIP_MEM_ALIGN_BUFFER(sizeof (char *) + sizeof (char *) * 2 + sizeof (struct in6_addr) + DNS_MAX_NAME_LENGTH + 1)
+#else
+#define HOSTENT_BUFLEN LWIP_MEM_ALIGN_BUFFER(sizeof (char *) + sizeof (char *) * 2 + sizeof (struct in_addr) + DNS_MAX_NAME_LENGTH + 1)
+#endif
 
 /** h_errno is exported in netdb.h for access by applications. */
 #if LWIP_DNS_API_DECLARE_H_ERRNO
@@ -72,12 +71,51 @@ int h_errno;
 #define LWIP_DNS_API_HOSTENT_STORAGE 0
 #endif
 
-/* define "hostent" variables storage */
+/* hostent storage */
+#if !LWIP_DNS_API_HOSTENT_STORAGE
+static struct hostent s_hostent;
+static char s_buffer[HOSTENT_BUFLEN];
+#endif /* LWIP_DNS_API_HOSTENT_STORAGE */
+
+/* forward declarations */
+static int lwip_gethostbyname_addrtype(const char *name, u8_t type, struct hostent *ret,
+                                       char *buf, size_t buflen, int *h_errnop);
+
+/**
+ * Returns an entry containing addresses of address family AF_INET
+ * for the host with name name.
+ * Due to dns_gethostbyname limitations, only one address is returned.
+ *
+ * @param name the hostname to resolve
+ * @return an entry containing addresses of address family AF_INET
+ *         for the host with name name
+ */
+struct hostent *
+lwip_gethostbyname(const char *name)
+{
+  err_t err;
+  int lh_errno;
+
+  /* hostent storage */
+#if LWIP_DNS_API_HOSTENT_STORAGE
+  struct hostent s_hostent;
+  char s_buffer[HOSTENT_BUFLEN];
+#endif /* LWIP_DNS_API_HOSTENT_STORAGE */
+
+  err = lwip_gethostbyname_addrtype(name, NETCONN_DNS_DEFAULT, &s_hostent, s_buffer, HOSTENT_BUFLEN, &lh_errno);
+
+  if (err != 0) {
+    h_errno = lh_errno;
+    return NULL;
+  }
+
 #if LWIP_DNS_API_HOSTENT_STORAGE
-#define HOSTENT_STORAGE
+  /* this function should return the "per-thread" hostent after copy from s_hostent */
+  return sys_thread_hostent(&s_hostent);
 #else
-#define HOSTENT_STORAGE static
-#endif /* LWIP_DNS_API_STATIC_HOSTENT */
+  return &s_hostent;
+#endif /* LWIP_DNS_API_HOSTENT_STORAGE */
+}
 
 /**
  * Returns an entry containing addresses of address family AF_INET
@@ -85,58 +123,47 @@ int h_errno;
  * Due to dns_gethostbyname limitations, only one address is returned.
  *
  * @param name the hostname to resolve
+ * @param af the address type to resolve
  * @return an entry containing addresses of address family AF_INET
  *         for the host with name name
  */
 struct hostent *
-lwip_gethostbyname(const char *name)
+lwip_gethostbyname2(const char *name, int af)
 {
+  int type;
   err_t err;
-  ip_addr_t addr;
+  int lh_errno;
 
-  /* buffer variables for lwip_gethostbyname() */
-  HOSTENT_STORAGE struct hostent s_hostent;
-  HOSTENT_STORAGE char *s_aliases;
-  HOSTENT_STORAGE ip_addr_t s_hostent_addr;
-  HOSTENT_STORAGE ip_addr_t *s_phostent_addr[2];
-  HOSTENT_STORAGE char s_hostname[DNS_MAX_NAME_LENGTH + 1];
+  /* hostent storage */
+#if LWIP_DNS_API_HOSTENT_STORAGE
+  struct hostent s_hostent;
+  char s_buffer[HOSTENT_BUFLEN];
+#endif /* LWIP_DNS_API_HOSTENT_STORAGE */
 
-  /* query host IP address */
-  err = netconn_gethostbyname(name, &addr);
-  if (err != ERR_OK) {
-    LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));
-    h_errno = HOST_NOT_FOUND;
+  if (af != AF_INET && af != AF_INET6) {
+    /* unknown address type */
+    h_errno = EINVAL;
+    return NULL;
+#if LWIP_IPV4
+  } else if (af == AF_INET) {
+    type = NETCONN_DNS_IPV4;
+#endif
+#if LWIP_IPV6
+  } else if (af == AF_INET6) {
+    type = NETCONN_DNS_IPV6;
+#endif
+  } else {
+    /* unsupported address type */
+    h_errno = EINVAL;
     return NULL;
   }
 
-  /* fill hostent */
-  s_hostent_addr = addr;
-  s_phostent_addr[0] = &s_hostent_addr;
-  s_phostent_addr[1] = NULL;
-  strncpy(s_hostname, name, DNS_MAX_NAME_LENGTH);
-  s_hostname[DNS_MAX_NAME_LENGTH] = 0;
-  s_hostent.h_name = s_hostname;
-  s_aliases = NULL;
-  s_hostent.h_aliases = &s_aliases;
-  s_hostent.h_addrtype = AF_INET;
-  s_hostent.h_length = sizeof(ip_addr_t);
-  s_hostent.h_addr_list = (char **)&s_phostent_addr;
+  err = lwip_gethostbyname_addrtype(name, type, &s_hostent, s_buffer, HOSTENT_BUFLEN, &lh_errno);
 
-#if DNS_DEBUG
-  /* dump hostent */
-  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name           == %s\n", s_hostent.h_name));
-  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases        == %p\n", (void *)s_hostent.h_aliases));
-  /* h_aliases are always empty */
-  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype       == %d\n", s_hostent.h_addrtype));
-  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length         == %d\n", s_hostent.h_length));
-  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list      == %p\n", (void *)s_hostent.h_addr_list));
-  if (s_hostent.h_addr_list != NULL) {
-    u8_t idx;
-    for (idx = 0; s_hostent.h_addr_list[idx]; idx++) {
-      LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, ipaddr_ntoa(s_phostent_addr[idx])));
-    }
+  if (err != 0) {
+    h_errno = lh_errno;
+    return NULL;
   }
-#endif /* DNS_DEBUG */
 
 #if LWIP_DNS_API_HOSTENT_STORAGE
   /* this function should return the "per-thread" hostent after copy from s_hostent */
@@ -167,9 +194,6 @@ lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
                      size_t buflen, struct hostent **result, int *h_errnop)
 {
   err_t err;
-  struct gethostbyname_r_helper *h;
-  char *hostname;
-  size_t namelen;
   int lh_errno;
 
   if (h_errnop == NULL) {
@@ -190,37 +214,85 @@ lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
     return -1;
   }
 
-  namelen = strlen(name);
-  if (buflen < (sizeof(struct gethostbyname_r_helper) + LWIP_MEM_ALIGN_BUFFER(namelen + 1))) {
-    /* buf can't hold the data needed + a copy of name */
-    *h_errnop = ERANGE;
+  err = lwip_gethostbyname_addrtype(name, NETCONN_DNS_DEFAULT, ret, buf, buflen, h_errnop);
+
+  if (err != 0) {
     return -1;
   }
 
-  h = (struct gethostbyname_r_helper *)LWIP_MEM_ALIGN(buf);
-  hostname = ((char *)h) + sizeof(struct gethostbyname_r_helper);
+  /* set result != NULL */
+  *result = ret;
 
-  /* query host IP address */
-  err = netconn_gethostbyname(name, &h->addr);
-  if (err != ERR_OK) {
-    LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));
-    *h_errnop = HOST_NOT_FOUND;
+  /* return success */
+  return 0;
+}
+
+/**
+ * Thread-safe variant of lwip_gethostbyname2: instead of using a static
+ * buffer, this function takes buffer and errno pointers as arguments
+ * and uses these for the result.
+ *
+ * @param name the hostname to resolve
+ * @param af the address type to resolve
+ * @param ret pre-allocated struct where to store the result
+ * @param buf pre-allocated buffer where to store additional data
+ * @param buflen the size of buf
+ * @param result pointer to a hostent pointer that is set to ret on success
+ *               and set to zero on error
+ * @param h_errnop pointer to an int where to store errors (instead of modifying
+ *                 the global h_errno)
+ * @return 0 on success, non-zero on error, additional error information
+ *         is stored in *h_errnop instead of h_errno to be thread-safe
+ */
+int
+lwip_gethostbyname2_r(const char *name, int af, struct hostent *ret, char *buf,
+                      size_t buflen, struct hostent **result, int *h_errnop)
+{
+  int type;
+  err_t err;
+  int lh_errno;
+
+  if (h_errnop == NULL) {
+    /* ensure h_errnop is never NULL */
+    h_errnop = &lh_errno;
+  }
+
+  if (result == NULL) {
+    /* not all arguments given */
+    *h_errnop = EINVAL;
+    return -1;
+  }
+  /* first thing to do: set *result to nothing */
+  *result = NULL;
+  if ((name == NULL) || (ret == NULL) || (buf == NULL)) {
+    /* not all arguments given */
+    *h_errnop = EINVAL;
     return -1;
   }
 
-  /* copy the hostname into buf */
-  MEMCPY(hostname, name, namelen);
-  hostname[namelen] = 0;
+  if (af != AF_INET && af != AF_INET6) {
+    /* unknown address type */
+    *h_errnop = EINVAL;
+    return -1;
+#if LWIP_IPV4
+  } else if (af == AF_INET) {
+    type = NETCONN_DNS_IPV4;
+#endif
+#if LWIP_IPV6
+  } else if (af == AF_INET6) {
+    type = NETCONN_DNS_IPV6;
+#endif
+  } else {
+    /* unsupported address type */
+    *h_errnop = EINVAL;
+    return -1;
+  }
 
-  /* fill hostent */
-  h->addr_list[0] = &h->addr;
-  h->addr_list[1] = NULL;
-  h->aliases = NULL;
-  ret->h_name = hostname;
-  ret->h_aliases = &h->aliases;
-  ret->h_addrtype = AF_INET;
-  ret->h_length = sizeof(ip_addr_t);
-  ret->h_addr_list = (char **)&h->addr_list;
+  err = lwip_gethostbyname_addrtype(name, type, ret, buf, buflen, h_errnop);
+
+  if (err != 0) {
+    return -1;
+  }
 
   /* set result != NULL */
   *result = ret;
@@ -229,6 +301,100 @@ lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
   return 0;
 }
 
+/**
+ * Support routine for lwip_gethostbyname* that takes buffer and errno pointer as
+ * arguments and additionally allows the requested address type to be set.
+ *
+ * @param name the hostname to resolve
+ * @param type address type to resolve (passed to netconn_gethostbyname_addrtype)
+ * @param ret pre-allocated struct where to store the result
+ * @param buf pre-allocated buffer where to store additional data
+ * @param buflen the size of buf
+ * @param h_errnop pointer to an int where to store errors (instead of modifying
+ *                 the global h_errno)
+ * @return 0 on success, non-zero on error, additional error information
+ *         is stored in *h_errnop instead of h_errno to be thread-safe
+ */
+static int
+lwip_gethostbyname_addrtype(const char *name, u8_t type, struct hostent *ret,
+                            char *buf, size_t buflen, int *h_errnop)
+{
+  err_t err;
+  ip_addr_t addr;
+
+  /* query host IP address */
+  err = netconn_gethostbyname_addrtype(name, &addr, type);
+  if (err != ERR_OK) {
+    LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname_addrtype(%s) failed, err=%d\n", name, err));
+    *h_errnop = HOST_NOT_FOUND;
+    return -1;
+  }
+
+  /* fill hostent */
+  if (IP_IS_V4_VAL(addr)) {
+#if LWIP_IPV4
+    if (buf + buflen - (char *)LWIP_MEM_ALIGN(buf) < sizeof (char *) + sizeof (char *) * 2 + sizeof (struct in_addr) + strlen(name) + 1) {
+      *h_errnop = ERANGE;
+      return -1;
+    }
+    ret->h_aliases = LWIP_MEM_ALIGN(buf);
+    ret->h_aliases[0] = NULL;
+    ret->h_addr_list = ret->h_aliases + 1;
+    ret->h_addr_list[0] = (char *)(ret->h_addr_list + 2);
+    ret->h_addr_list[1] = NULL;
+    ret->h_addrtype = AF_INET;
+    ret->h_length = sizeof (struct in_addr);
+    inet_addr_from_ip4addr((struct in_addr *)ret->h_addr_list[0], ip_2_ip4(&addr));
+    ret->h_name = ret->h_addr_list[0] + ret->h_length;
+    strcpy(ret->h_name, name);
+#endif /* LWIP_IPV4 */
+  } else {
+#if LWIP_IPV6
+    if (buf + buflen - (char *)LWIP_MEM_ALIGN(buf) < sizeof (char *) + sizeof (char *) * 2 + sizeof (struct in6_addr) + strlen(name) + 1) {
+      *h_errnop = ERANGE;
+      return -1;
+    }
+    ret->h_aliases = LWIP_MEM_ALIGN(buf);
+    ret->h_aliases[0] = NULL;
+    ret->h_addr_list = ret->h_aliases + 1;
+    ret->h_addr_list[0] = (char *)(ret->h_addr_list + 2);
+    ret->h_addr_list[1] = NULL;
+    ret->h_addrtype = AF_INET6;
+    ret->h_length = sizeof (struct in6_addr);
+    inet6_addr_from_ip6addr((struct in6_addr *)ret->h_addr_list[0], ip_2_ip6(&addr));
+    ret->h_name = ret->h_addr_list[0] + ret->h_length;
+    strcpy(ret->h_name, name);
+#endif /* LWIP_IPV6 */
+  }
+
+#if DNS_DEBUG
+  /* dump hostent */
+  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name           == %s\n", ret->h_name));
+  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases        == %p\n", (void *)ret->h_aliases));
+  /* h_aliases are always empty */
+  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype       == %d\n", ret->h_addrtype));
+  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length         == %d\n", ret->h_length));
+  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list      == %p\n", (void *)ret->h_addr_list));
+  if (ret->h_addr_list != NULL) {
+    u8_t idx;
+    for (idx = 0; ret->h_addr_list[idx]; idx++) {
+#if LWIP_IPV4
+      if (ret->h_addrtype == AF_INET) {
+        LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, inet_ntoa(*(struct in_addr *)ret->h_addr_list[idx])));
+      }
+#endif
+#if LWIP_IPV6
+      if (ret->h_addrtype == AF_INET6) {
+        LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, inet6_ntoa(*(struct in_addr *)ret->h_addr_list[idx])));
+      }
+#endif
+    }
+  }
+#endif /* DNS_DEBUG */
+
+  return 0;
+}
+
 /**
  * Frees one or more addrinfo structures returned by getaddrinfo(), along with
  * any additional storage associated with those structures. If the ai_next field
diff --git a/src/include/lwip/netdb.h b/src/include/lwip/netdb.h
index d3d15dfa..57b63def 100644
--- a/src/include/lwip/netdb.h
+++ b/src/include/lwip/netdb.h
@@ -120,8 +120,11 @@ extern int h_errno;
 #endif /* LWIP_DNS_API_DECLARE_H_ERRNO*/
 
 struct hostent *lwip_gethostbyname(const char *name);
+struct hostent *lwip_gethostbyname2(const char *name, int af);
 int lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
                 size_t buflen, struct hostent **result, int *h_errnop);
+int lwip_gethostbyname2_r(const char *name, int af, struct hostent *ret, char *buf,
+                size_t buflen, struct hostent **result, int *h_errnop);
 void lwip_freeaddrinfo(struct addrinfo *ai);
 int lwip_getaddrinfo(const char *nodename,
        const char *servname,
@@ -132,9 +135,14 @@ int lwip_getaddrinfo(const char *nodename,
 /** @ingroup netdbapi */
 #define gethostbyname(name) lwip_gethostbyname(name)
 /** @ingroup netdbapi */
+#define gethostbyname2(name, af) lwip_gethostbyname2(name, af)
+/** @ingroup netdbapi */
 #define gethostbyname_r(name, ret, buf, buflen, result, h_errnop) \
        lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop)
 /** @ingroup netdbapi */
+#define gethostbyname2_r(name, af, ret, buf, buflen, result, h_errnop)   \
+       lwip_gethostbyname2_r(name, af, ret, buf, buflen, result, h_errnop)
+/** @ingroup netdbapi */
 #define freeaddrinfo(addrinfo) lwip_freeaddrinfo(addrinfo)
 /** @ingroup netdbapi */
 #define getaddrinfo(nodname, servname, hints, res) \
