diff --git a/src/api/netdb.c b/src/api/netdb.c
index e07ab049..f80b312b 100644
--- a/src/api/netdb.c
+++ b/src/api/netdb.c
@@ -32,6 +32,7 @@
  * This file is part of the lwIP TCP/IP stack.
  *
  * Author: Simon Goldschmidt
+ *         Simon Kueppers (2pi-Labs GmbH)
  *
  */
 
@@ -248,6 +249,62 @@ lwip_freeaddrinfo(struct addrinfo *ai)
   }
 }
 
+/**
+ * Allocates an addrinfo struct and appends it to the given list.
+ *
+ * @param list pointer to a linked list item to append the new addrinfo struct to.
+ *             If the item is NULL, a new list will be started.
+ * @param family family of socket address within the new addrinfo struct
+ * @return pointer to new item or NULL if memory could not be allocated
+ */
+static struct addrinfo *
+lwip_allocaddrinfo(struct addrinfo ** list, int family)
+{
+  struct addrinfo *ai;
+  struct sockaddr_storage *sa = NULL;
+
+  ai = (struct addrinfo *)memp_malloc(MEMP_NETDB);
+  if (ai == NULL) {
+    return NULL;
+  }
+  memset(ai, 0, NETDB_ELEM_SIZE);
+  /* cast through void* to get rid of alignment warnings */
+  sa = (struct sockaddr_storage *)(void *)((u8_t *)ai + sizeof(struct addrinfo));
+  if (family == AF_INET6) {
+#if LWIP_IPV6
+    /* initialize sockaddr */
+    struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
+    sa6->sin6_family = AF_INET6;
+    sa6->sin6_len = sizeof(struct sockaddr_in6);
+#endif /* LWIP_IPV6 */
+  } else {
+#if LWIP_IPV4
+    struct sockaddr_in *sa4 = (struct sockaddr_in *)sa;
+    /* initialize sockaddr */
+    sa4->sin_family = AF_INET;
+    sa4->sin_len = sizeof(struct sockaddr_in);
+#endif /* LWIP_IPV4 */
+  }
+
+  ai->ai_addrlen = sizeof(struct sockaddr_storage);
+  ai->ai_addr = (struct sockaddr *)sa;
+  ai->ai_family = family;
+
+  if (*list == NULL) {
+    /* start new list */
+    *list = ai;
+  } else {
+    /* append to list */
+    struct addrinfo * item = *list;
+    while(item->ai_next != NULL) {
+      item = item->ai_next;
+    }
+    item->ai_next = ai;
+  }
+
+  return ai;
+}
+
 /**
  * Translates the name of a service location (for example, a host name) and/or
  * a service name and returns a set of socket addresses and associated
@@ -256,14 +313,14 @@ lwip_freeaddrinfo(struct addrinfo *ai)
  * Memory for the result is allocated internally and must be freed by calling
  * lwip_freeaddrinfo()!
  *
- * Due to a limitation in dns_gethostbyname, only the first address of a
- * host is returned.
+ * Due to a limitation in dns_gethostbyname, two successive DNS resolver calls
+ * are carried out, when ai_family is not specified in hints.
  * Also, service names are not supported (only port numbers)!
  *
  * @param nodename descriptive name or address string of the host
  *                 (may be NULL -> local address)
  * @param servname port number as string of NULL
- * @param hints structure containing input values that set socktype and protocol
+ * @param hints structure containing input values that set flags, socktype, protocol and family
  * @param res pointer to a pointer where to store the result (set to NULL on failure)
  * @return 0 on success, non-zero on failure
  *
@@ -273,14 +330,18 @@ int
 lwip_getaddrinfo(const char *nodename, const char *servname,
                  const struct addrinfo *hints, struct addrinfo **res)
 {
-  err_t err;
-  ip_addr_t addr;
   struct addrinfo *ai;
-  struct sockaddr_storage *sa = NULL;
+  struct addrinfo *list = NULL;
   int port_nr = 0;
-  size_t total_size;
-  size_t namelen = 0;
   int ai_family;
+  int ai_flags;
+  int ai_socktype;
+  int ai_protocol;
+  int socktypes[] = LWIP_DNS_API_SOCKTYPES;
+  int protocols[] = LWIP_DNS_API_PROTOCOLS;
+
+  LWIP_ASSERT("LWIP_DNS_API_SOCKTYPES must have the same number of entries as LWIP_DNS_API_PROTOCOLS",
+          sizeof(socktypes) == sizeof(protocols));
 
   if (res == NULL) {
     return EAI_FAIL;
@@ -302,8 +363,49 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
        ) {
       return EAI_FAMILY;
     }
+
+    ai_socktype = hints->ai_socktype;
+    ai_protocol = hints->ai_protocol;
+    if (ai_protocol != 0) {
+      if ( (ai_protocol != IPPROTO_UDP) &&
+           (ai_protocol != IPPROTO_TCP) &&
+           (ai_protocol != IPPROTO_IP) ) {
+        /* Unsupported protocol */
+        return EAI_SERVICE;
+      }
+    }
+    if (ai_socktype != 0) {
+      if ( (ai_socktype != SOCK_DGRAM) &&
+           (ai_socktype != SOCK_STREAM) &&
+           (ai_socktype != SOCK_RAW) ) {
+        /* Unsupported socktype */
+        return EAI_SOCKTYPE;
+      }
+    }
+    if ( (ai_protocol != 0) && (ai_socktype != 0) ) {
+      /* Both ai_protocol and ai_socktype are given, see if they match */
+      if ( ( (ai_socktype == SOCK_DGRAM) && (ai_protocol != IPPROTO_UDP) ) ||
+           ( (ai_socktype == SOCK_STREAM) && (ai_protocol != IPPROTO_TCP) ) ||
+           ( (ai_socktype == SOCK_RAW) && (ai_protocol != IPPROTO_IP) ) ) {
+        /* The requested socket type is not supported.  This could
+         * occur, for example, if hints.ai_socktype and
+         * hints.ai_protocol are inconsistent (e.g., SOCK_DGRAM and
+         * IPPROTO_TCP, respectively). */
+        return EAI_SOCKTYPE;
+      }
+    }
+
+    ai_flags = hints->ai_flags;
+    if ( (ai_flags & AI_CANONNAME) && (nodename == NULL) ) {
+      /* AI_CANONNAME is not valid for non-client usage */
+      return EAI_BADFLAGS;
+    }
   } else {
+    /* set default values (hints == NULL) */
     ai_family = AF_UNSPEC;
+    ai_flags = 0;
+    ai_socktype = 0;
+    ai_protocol = 0;
   }
 
   if (servname != NULL) {
@@ -319,102 +421,213 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
     }
   }
 
-  if (nodename != NULL) {
+  if (nodename == NULL) {
+    /* service location is not specified, use loopback or wildcard address */
+    int families[] = LWIP_DNS_API_FAMILIES_LOCAL;
+#if LWIP_IPV4
+    ip4_addr_t addr4;
+#endif
+#if LWIP_IPV6
+    ip6_addr_t addr6;
+#endif
+
+    if (ai_flags & AI_PASSIVE) {
+      /* The returned socket addresses will be suitable for
+       * binding a socket that will accept connections.  The
+       * returned socket address will contain the "wildcard address"
+       * (INADDR_ANY for IPv4 addresses, IN6ADDR_ANY_INIT for IPv6
+       * address).  The wildcard address is used by applications
+       * (typically servers) that intend to accept connections on any of
+       * the host's network addresses. */
+#if LWIP_IPV4
+      ip4_addr_set_any(&addr4);
+#endif
+#if LWIP_IPV6
+      ip6_addr_set_any(&addr6);
+#endif
+    } else {
+      /* If the AI_PASSIVE flag is not set in ai_flags, then the
+       * returned socket addresses will be suitable for use with
+       * connect(2), sendto(2), or sendmsg(2).  If node is NULL, then the
+       * network address will be set to the loopback interface address
+       * (INADDR_LOOPBACK for IPv4 addresses, IN6ADDR_LOOPBACK_INIT for
+       * IPv6 address); this is used by applications that intend to
+       * communicate with peers running on the same host. */
+#if LWIP_IPV4
+      ip4_addr_set_loopback(&addr4);
+#endif
+#if LWIP_IPV6
+      ip6_addr_set_loopback(&addr6);
+#endif
+    }
+
+    for (int i=0; i<sizeof(families)/sizeof(*families); i++) {
+      int family = families[i];
+
+      if ( (ai_family == family) || (ai_family == AF_UNSPEC) ) {
+        /* This is the selected family or no family was specified (include any) */
+        for (int j=0; j<sizeof(socktypes)/sizeof(*socktypes); j++) {
+          int socktype = socktypes[j];
+          int protocol = protocols[j];
+
+          if ( ( (ai_socktype != 0) && (ai_socktype == socktype) ) ||
+               ( (ai_protocol != 0) && (ai_protocol == protocol) ) ||
+               ( (ai_socktype == 0) && (ai_protocol == 0) ) ) {
+            /* This is the selected socktype or the selected protocol or
+             * neither socktype nor protocol was specified (include all). */
+
+            if (family == AF_INET) {
+#if LWIP_IPV4
+              ai = lwip_allocaddrinfo(&list, AF_INET);
+              if (ai == NULL) {
+                lwip_freeaddrinfo(list);
+                return EAI_MEMORY;
+              }
+              ai->ai_socktype = socktype;
+              ai->ai_protocol = protocol;
+              struct sockaddr_in *sa4 = (struct sockaddr_in *) ai->ai_addr;
+              inet_addr_from_ip4addr(&sa4->sin_addr, &addr4);
+              sa4->sin_port = lwip_htons((u16_t)port_nr);
+#endif
+            } else if (family == AF_INET6) {
+#if LWIP_IPV6
+              ai = lwip_allocaddrinfo(&list, AF_INET6);
+              if (ai == NULL) {
+                lwip_freeaddrinfo(list);
+                return EAI_MEMORY;
+              }
+              ai->ai_socktype = socktype;
+              ai->ai_protocol = protocol;
+              struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) ai->ai_addr;
+              inet6_addr_from_ip6addr(&sa6->sin6_addr, &addr6);
+              sa6->sin6_scope_id = ip6_addr_zone(&addr6);
+              sa6->sin6_port = lwip_htons((u16_t)port_nr);
+#endif
+            }
+          }
+        }
+      }
+    }
+  } else {
     /* service location specified, try to resolve */
-    if ((hints != NULL) && (hints->ai_flags & AI_NUMERICHOST)) {
+    size_t total_size;
+    size_t namelen = 0;
+    err_t err;
+    ip_addr_t addr;
+    u8_t success = 0;
+
+    /* check nodename length */
+    total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_storage);
+    if (nodename != NULL) {
+      namelen = strlen(nodename);
+      if (namelen > DNS_MAX_NAME_LENGTH) {
+        /* invalid name length */
+        return EAI_FAIL;
+      }
+      LWIP_ASSERT("namelen is too long", total_size + namelen + 1 > total_size);
+      total_size += namelen + 1;
+    }
+    /* If this fails, please report to lwip-devel! :-) */
+    LWIP_ASSERT("total_size <= NETDB_ELEM_SIZE: please report this!",
+                total_size <= NETDB_ELEM_SIZE);
+
+    if (ai_flags & AI_NUMERICHOST) {
       /* no DNS lookup, just parse for an address string */
       if (!ipaddr_aton(nodename, &addr)) {
         return EAI_NONAME;
       }
-#if LWIP_IPV4 && LWIP_IPV6
+
       if ((IP_IS_V6_VAL(addr) && ai_family == AF_INET) ||
           (IP_IS_V4_VAL(addr) && ai_family == AF_INET6)) {
-        return EAI_NONAME;
+        return EAI_ADDRFAMILY;
       }
-#endif /* LWIP_IPV4 && LWIP_IPV6 */
-    } else {
-#if LWIP_IPV4 && LWIP_IPV6
-      /* AF_UNSPEC: prefer IPv4 */
-      u8_t type = NETCONN_DNS_IPV4_IPV6;
-      if (ai_family == AF_INET) {
-        type = NETCONN_DNS_IPV4;
-      } else if (ai_family == AF_INET6) {
-        type = NETCONN_DNS_IPV6;
+      success++;
+    }
+
+    int families[] = LWIP_DNS_API_FAMILIES;
+
+    for (int i=0; i<sizeof(families)/sizeof(*families); i++) {
+      int family = families[i];
+
+      if (!(ai_flags & AI_NUMERICHOST)) {
+        /* Resolve host via DNS if AI_NUMERICHOST is not set */
+        u8_t type = family == AF_INET ? NETCONN_DNS_IPV4 : NETCONN_DNS_IPV6;
+        err = netconn_gethostbyname_addrtype(nodename, &addr, type);
+        if (err != ERR_OK) {
+          /* Try next family */
+          continue;
+        }
+        success++;
       }
-#endif /* LWIP_IPV4 && LWIP_IPV6 */
-      err = netconn_gethostbyname_addrtype(nodename, &addr, type);
-      if (err != ERR_OK) {
-        return EAI_FAIL;
+
+      if ( (ai_family == family) || (ai_family == AF_UNSPEC) ) {
+        /* This family is eligible */
+        if ((IP_IS_V4_VAL(addr) && family == AF_INET) ||
+            (IP_IS_V6_VAL(addr) && family == AF_INET6)) {
+          /* The resolved address matches this family, add this address */
+          for (int j=0; j<sizeof(socktypes)/sizeof(*socktypes); j++) {
+            int socktype = socktypes[j];
+            int protocol = protocols[j];
+
+            if ( ( (ai_socktype != 0) && (ai_socktype == socktype) ) ||
+                 ( (ai_protocol != 0) && (ai_protocol == protocol) ) ||
+                 ( (ai_socktype == 0) && (ai_protocol == 0) ) ) {
+              /* This is the selected socktype or the selected protocol or
+               * neither socktype nor protocol was specified (include all). */
+              if (family == AF_INET) {
+#if LWIP_IPV4
+                ai = lwip_allocaddrinfo(&list, AF_INET);
+                if (ai == NULL) {
+                  lwip_freeaddrinfo(list);
+                  return EAI_MEMORY;
+                }
+                ai->ai_socktype = socktype;
+                ai->ai_protocol = protocol;
+                struct sockaddr_in *sa4 = (struct sockaddr_in *) ai->ai_addr;
+                inet_addr_from_ip4addr(&sa4->sin_addr, ip_2_ip4(&addr));
+                sa4->sin_port = lwip_htons((u16_t)port_nr);
+#endif
+              } else if (family == AF_INET6) {
+#if LWIP_IPV6
+                ai = lwip_allocaddrinfo(&list, AF_INET6);
+                if (ai == NULL) {
+                  lwip_freeaddrinfo(list);
+                  return EAI_MEMORY;
+                }
+                ai->ai_socktype = socktype;
+                ai->ai_protocol = protocol;
+                struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) ai->ai_addr;
+                inet6_addr_from_ip6addr(&sa6->sin6_addr, ip_2_ip6(&addr));
+                sa6->sin6_port = lwip_htons((u16_t)port_nr);
+                sa6->sin6_scope_id = ip6_addr_zone(ip_2_ip6(&addr));
+#endif
+              }
+            }
+          }
+        }
       }
     }
-  } else {
-    /* service location specified, use loopback address */
-    if ((hints != NULL) && (hints->ai_flags & AI_PASSIVE)) {
-      ip_addr_set_any_val(ai_family == AF_INET6, addr);
-    } else {
-      ip_addr_set_loopback_val(ai_family == AF_INET6, addr);
-    }
-  }
 
-  total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_storage);
-  if (nodename != NULL) {
-    namelen = strlen(nodename);
-    if (namelen > DNS_MAX_NAME_LENGTH) {
-      /* invalid name length */
-      return EAI_FAIL;
+    if (list == NULL) {
+      if (success > 0) {
+          /* The specified network host exists, but does not have any
+           * network addresses defined. */
+          return EAI_NODATA;
+      } else {
+          /* The node or service is not known */
+          return EAI_NONAME;
+      }
     }
-    LWIP_ASSERT("namelen is too long", total_size + namelen + 1 > total_size);
-    total_size += namelen + 1;
-  }
-  /* If this fails, please report to lwip-devel! :-) */
-  LWIP_ASSERT("total_size <= NETDB_ELEM_SIZE: please report this!",
-              total_size <= NETDB_ELEM_SIZE);
-  ai = (struct addrinfo *)memp_malloc(MEMP_NETDB);
-  if (ai == NULL) {
-    return EAI_MEMORY;
-  }
-  memset(ai, 0, total_size);
-  /* cast through void* to get rid of alignment warnings */
-  sa = (struct sockaddr_storage *)(void *)((u8_t *)ai + sizeof(struct addrinfo));
-  if (IP_IS_V6_VAL(addr)) {
-#if LWIP_IPV6
-    struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
-    /* set up sockaddr */
-    inet6_addr_from_ip6addr(&sa6->sin6_addr, ip_2_ip6(&addr));
-    sa6->sin6_family = AF_INET6;
-    sa6->sin6_len = sizeof(struct sockaddr_in6);
-    sa6->sin6_port = lwip_htons((u16_t)port_nr);
-    sa6->sin6_scope_id = ip6_addr_zone(ip_2_ip6(&addr));
-    ai->ai_family = AF_INET6;
-#endif /* LWIP_IPV6 */
-  } else {
-#if LWIP_IPV4
-    struct sockaddr_in *sa4 = (struct sockaddr_in *)sa;
-    /* set up sockaddr */
-    inet_addr_from_ip4addr(&sa4->sin_addr, ip_2_ip4(&addr));
-    sa4->sin_family = AF_INET;
-    sa4->sin_len = sizeof(struct sockaddr_in);
-    sa4->sin_port = lwip_htons((u16_t)port_nr);
-    ai->ai_family = AF_INET;
-#endif /* LWIP_IPV4 */
-  }
 
-  /* set up addrinfo */
-  if (hints != NULL) {
-    /* copy socktype & protocol from hints if specified */
-    ai->ai_socktype = hints->ai_socktype;
-    ai->ai_protocol = hints->ai_protocol;
-  }
-  if (nodename != NULL) {
-    /* copy nodename to canonname if specified */
-    ai->ai_canonname = ((char *)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_storage));
-    MEMCPY(ai->ai_canonname, nodename, namelen);
-    ai->ai_canonname[namelen] = 0;
+    if ( (nodename != NULL) && (ai_flags & AI_CANONNAME) ){
+      /* copy canonname directly from nodename to first element, if AI_CANONNAME specified */
+      list->ai_canonname = ((char *)list + sizeof(struct addrinfo) + sizeof(struct sockaddr_storage));
+      MEMCPY(list->ai_canonname, nodename, namelen);
+      list->ai_canonname[namelen] = 0;
+    }
   }
-  ai->ai_addrlen = sizeof(struct sockaddr_storage);
-  ai->ai_addr = (struct sockaddr *)sa;
 
-  *res = ai;
+  *res = list;
 
   return 0;
 }
diff --git a/src/include/lwip/netdb.h b/src/include/lwip/netdb.h
index d3d15dfa..25c68474 100644
--- a/src/include/lwip/netdb.h
+++ b/src/include/lwip/netdb.h
@@ -63,6 +63,22 @@ extern "C" {
 #define LWIP_DNS_API_DECLARE_STRUCTS  1
 #endif
 
+#ifndef LWIP_DNS_API_FAMILIES
+#define LWIP_DNS_API_FAMILIES         {AF_INET, AF_INET6}
+#endif
+
+#ifndef LWIP_DNS_API_FAMILIES_LOCAL
+#define LWIP_DNS_API_FAMILIES_LOCAL   LWIP_DNS_API_FAMILIES
+#endif
+
+#ifndef LWIP_DNS_API_SOCKTYPES
+#define LWIP_DNS_API_SOCKTYPES        {SOCK_STREAM, SOCK_DGRAM, SOCK_RAW}
+#endif
+
+#ifndef LWIP_DNS_API_PROTOCOLS
+#define LWIP_DNS_API_PROTOCOLS        {IPPROTO_TCP, IPPROTO_UDP, IPPROTO_IP}
+#endif
+
 #if LWIP_DNS_API_DEFINE_ERRORS
 /** Errors used by the DNS API functions, h_errno can be one of them */
 #define EAI_NONAME      200
@@ -70,6 +86,10 @@ extern "C" {
 #define EAI_FAIL        202
 #define EAI_MEMORY      203
 #define EAI_FAMILY      204
+#define EAI_SOCKTYPE    205
+#define EAI_BADFLAGS    206
+#define EAI_ADDRFAMILY  207
+#define EAI_NODATA      208
 
 #define HOST_NOT_FOUND  210
 #define NO_DATA         211
