diff --git a/Usermode/Libraries/libnet.so_src/hostnames.c b/Usermode/Libraries/libnet.so_src/hostnames.c
index 203f4aa462aa66cdb773f54aa11e832545fd48f3..88093de37d1a3eb3a398564a22c1be784608c392 100644
--- a/Usermode/Libraries/libnet.so_src/hostnames.c
+++ b/Usermode/Libraries/libnet.so_src/hostnames.c
@@ -24,16 +24,23 @@ struct sHostEntry
 	char	*Names[];
 };
 
-struct sDNSCallbackInfo
+struct sLookupAnyInfo
 {
-	 int	expected_size;
+	 int	expected_type;
 	void	*dest_ptr;
+	bool	have_result;
+};
+struct sDNSCallbackInfo
+{
+	void	*cb_info;
+	tNet_LookupAddrs_Callback	*callback;
 	enum eTypes	desired_type;
 	enum eClass	desired_class;
-	bool	have_result;
+	bool	got_value;
 };
 
 // === PROTOTYPES ===
+ int	int_lookupany_callback(void *info_v, int AddrType, const void *Addr);
 void	int_DNS_callback(void *info, const char *name, enum eTypes type, enum eClass class, unsigned int ttl, size_t rdlength, const void *rdata);
 
 // === GLOBALS ===
@@ -44,6 +51,28 @@ struct sHostEntry	*gaHostEntries;
 
 // === CODE ===
 int Net_Lookup_AnyAddr(const char *Name, int AddrType, void *Addr)
+{
+	struct sLookupAnyInfo	cb_info = {
+		.expected_type = AddrType,
+		.dest_ptr = Addr,
+		.have_result = false,
+		};
+	return Net_Lookup_Addrs(Name, &cb_info, int_lookupany_callback);
+}
+int int_lookupany_callback(void *info_v, int AddrType, const void *Addr)
+{
+	struct sLookupAnyInfo	*info = info_v;
+	if( AddrType == info->expected_type && info->have_result == false )
+	{
+		memcpy(info->dest_ptr, Addr, Net_GetAddressSize(AddrType));
+		
+		info->have_result = true;
+		return 1;
+	}
+	return 0;
+}
+
+int Net_Lookup_Addrs(const char *Name, void *cb_info, tNet_LookupAddrs_Callback *callback)
 {
 	// 1. Load (if not loaded) the DNS config from "/Acess/Conf/dns"
 	// - "* <ip> <ip>" for DNS server(s)
@@ -53,33 +82,29 @@ int Net_Lookup_AnyAddr(const char *Name, int AddrType, void *Addr)
 	for( int i = 0; i < giNumHostEntries; i ++ )
 	{
 		const struct sHostEntry* he = &gaHostEntries[i];
-		if( he->AddrType == AddrType )
+		for( const char * const *namep = (const char**)he->Names; *namep; namep ++ )
 		{
-			for( const char * const *namep = (const char**)he->Names; *namep; namep ++ )
+			if( strcasecmp(Name, *namep) == 0 )
 			{
-				if( strcasecmp(Name, *namep) == 0 )
-				{
-					memcpy(Addr, he->AddrData, Net_GetAddressSize(AddrType));
+				if( callback(cb_info, he->AddrType, he->AddrData) != 0 )
 					return 0;
-				}
 			}
 		}
 	}
 	// 3. Contact DNS server specified in config
 	for( int i = 0; i < giNumDNSServers; i ++ )
 	{
-		// TODO
 		const struct sDNSServer	*s = &gaDNSServers[i];
 		struct sDNSCallbackInfo	info = {
-			.expected_size = Net_GetAddressSize(AddrType),
-			.dest_ptr = Addr,
+			.cb_info = cb_info,
+			.callback = callback,
 			.desired_type = TYPE_A,
 			.desired_class = CLASS_IN,
-			.have_result = false
+			.got_value = false,
 			};
 		if( ! DNS_Query(s->AddrType, s->AddrData, Name, info.desired_type, info.desired_class, int_DNS_callback, &info) )
 		{
-			if( info.have_result )
+			if( info.got_value )
 			{
 				return 0;
 			}
@@ -96,18 +121,30 @@ int Net_Lookup_AnyAddr(const char *Name, int AddrType, void *Addr)
 void int_DNS_callback(void *info_v, const char *name, enum eTypes type, enum eClass class, unsigned int ttl, size_t rdlength, const void *rdata)
 {
 	struct sDNSCallbackInfo	*info = info_v;
-	if( type == info->desired_type && class == info->desired_class && info->have_result == false )
+	
+	// Check type matches (if pattern was provided)
+	if( info->desired_type != QTYPE_STAR && type != info->desired_type )
+		return ;
+	if( info->desired_class != QCLASS_STAR && class != info->desired_class )
+		return ;
+	
+	switch( type )
 	{
-		// We're just working with A and AAAA, so copying from rdata is safe
-		if( rdlength != info->expected_size ) {
-			// ... oh, that's not good
+	case TYPE_A:
+		if( rdlength != 4 )
 			return ;
-		}
-		
-		memcpy(info->dest_ptr, rdata, rdlength);
-		
-		info->have_result = true;
+		info->callback( info->cb_info, 4, rdata );
+		break;
+	//case TYPE_AAAA:
+	//	if( rdlength != 16 )
+	//		return ;
+	//	info->callback( info->cb_info, 6, rdata );
+	//	break;
+	default:
+		// Ignore anything not A/AAAA
+		break;
 	}
+	info->got_value = true;
 }
 
 int Net_Lookup_Name(int AddrType, const void *Addr, char *Dest[256])
diff --git a/Usermode/Libraries/libnet.so_src/include/dns.h b/Usermode/Libraries/libnet.so_src/include/dns.h
index 8a6ba440a581ee97802035860c75368d923b73a6..62204f0513d2399b6dd8ae5e0f738dc6cab79f4c 100644
--- a/Usermode/Libraries/libnet.so_src/include/dns.h
+++ b/Usermode/Libraries/libnet.so_src/include/dns.h
@@ -28,7 +28,7 @@ enum eClass
 {
 	CLASS_IN,
 	CLASS_CH,	// "Chaos"
-	CLASS_STAR = 255,
+	QCLASS_STAR = 255,
 };
 
 /**
diff --git a/Usermode/Libraries/libnet.so_src/include_exp/net.h b/Usermode/Libraries/libnet.so_src/include_exp/net.h
index f02c0a433ccecac117f39bad7a8e90194aa540ab..cd2cb6c8e646a4fe899c9b806bef22481bef8e8c 100644
--- a/Usermode/Libraries/libnet.so_src/include_exp/net.h
+++ b/Usermode/Libraries/libnet.so_src/include_exp/net.h
@@ -72,6 +72,16 @@ extern int	Net_OpenSocket_UDP(int AddrType, const void *Addr, int RAddr, int LAd
  */
 extern int	Net_Lookup_AnyAddr(const char *Name, int AddrType, void *Addr);
 
+/**
+ * \brief Callback for Net_Lookup_Addrs, returns non-zero when lookup should terminate
+ */
+typedef int tNet_LookupAddrs_Callback(void *info, int AddrType, const void *Addr);
+
+/**
+ * \brief Enumerate addresses for a host, calling the provided function for each
+ */
+extern int	Net_Lookup_Addrs(const char *Name, void *info, tNet_LookupAddrs_Callback* callback);
+
 /**
  */
 extern int	Net_Lookup_Name(int AddrType, const void *Addr, char *Dest[256]);
diff --git a/Usermode/Libraries/libpsocket.so_src/getaddrinfo.c b/Usermode/Libraries/libpsocket.so_src/getaddrinfo.c
index 5c21c06ea555621970653f23049a3e832a75a6c9..e1a0e424a4266a297d44e08e594600cc262bdd5d 100644
--- a/Usermode/Libraries/libpsocket.so_src/getaddrinfo.c
+++ b/Usermode/Libraries/libpsocket.so_src/getaddrinfo.c
@@ -13,6 +13,16 @@
 #include <stdlib.h>	// strtol
 #include <acess/sys.h>
 
+// === TYPES ===
+struct sLookupInfo {
+	struct addrinfo	**ret_p;
+};
+
+// === PROTOTYPES ===
+struct addrinfo *int_new_addrinfo(int af, const void *addrdata);
+int int_getaddinfo_lookupcb(void *info, int addr_type, const void *addr);
+
+// === GLOBALS ===
 static const struct {
 	const char *Name;
 	 int	SockType;
@@ -52,28 +62,20 @@ int getaddrinfo(const char *node, const char *service, const struct addrinfo *hi
 	{
 		// 1. Check if the node is an IP address
 		{
-			 int	type;
 			char	addrdata[16];
-			type = Net_ParseAddress(node, addrdata);
+			int type = Net_ParseAddress(node, addrdata);
 			switch(type)
 			{
-			case 0:
+			case NET_ADDRTYPE_NULL:
 				break;
-			case 4:	// IPv4
-				ret = malloc(sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
-				ret->ai_family = AF_INET;
-				ret->ai_socktype = 0;
-				ret->ai_protocol = 0;
-				ret->ai_addrlen = sizeof(struct in_addr);
-				ret->ai_addr = (void*)( ret + 1 );
-				ret->ai_canonname = 0;
-				ret->ai_next = 0;
-				((struct sockaddr_in*)ret->ai_addr)->sin_family = AF_INET;
-				((struct sockaddr_in*)ret->ai_addr)->sin_port = 0;
-				memcpy( &((struct sockaddr_in*)ret->ai_addr)->sin_addr, addrdata, 4 );
+			case NET_ADDRTYPE_IPV4:
+				ret = int_new_addrinfo(AF_INET, addrdata);
+				break;
+			case NET_ADDRTYPE_IPV6:
+				ret = int_new_addrinfo(AF_INET6, addrdata);
 				break;
 			default:
-				_SysDebug("getaddrinfo: Unknown address family %i", type);
+				_SysDebug("getaddrinfo: Unknown address type %i", type);
 				return 1;
 			}
 		}
@@ -82,15 +84,19 @@ int getaddrinfo(const char *node, const char *service, const struct addrinfo *hi
 		// - No luck with above, and hints->ai_flags doesn't have AI_NUMERICHOST set
 		if( !ret && !(hints->ai_flags & AI_NUMERICHOST) )
 		{
-			_SysDebug("getaddrinfo: TODO DNS Lookups");
-			// TODO: DNS Lookups
-			// ? /Acess/Conf/Nameservers
-			// ? /Acess/Conf/Hosts
-			//count = Net_LookupDNS(node, service, NULL);
-			//
+			// Just does a basic A record lookup
+			// TODO: Support SRV records
+			// TODO: Ensure that CNAMEs are handled correctly
+			struct sLookupInfo info = {
+				.ret_p = &ret,
+				};
+			if( Net_Lookup_Addrs(node, &info, int_getaddinfo_lookupcb) ) {
+				// Lookup failed, quick return
+				return EAI_NONAME;
+			}
 		}
 		
-		// 3. No Match, chuck sad
+		// 3. No Match, return sad
 		if( !ret )
 		{
 			return EAI_NONAME;
@@ -182,9 +188,81 @@ int getaddrinfo(const char *node, const char *service, const struct addrinfo *hi
 	return 0;
 }
 
+/**
+ * \brief Allocate a new zeroed addrinfo for the specified address
+ */
+struct addrinfo *int_new_addrinfo(int af, const void *addrdata)
+{
+	size_t	addrlen = 0;
+	switch(af)
+	{
+	case AF_INET:
+		addrlen = sizeof(struct sockaddr_in);
+		break;
+	case AF_INET6:
+		addrlen = sizeof(struct sockaddr_in6);
+		break;
+	default:
+		_SysDebug("int_new_addrinfo: ERROR - Unknown AF %i", af);
+		return NULL;
+	}
+	struct addrinfo* ret = malloc(sizeof(struct addrinfo) + addrlen);
+	ret->ai_family = af;
+	ret->ai_socktype = 0;
+	ret->ai_protocol = 0;
+	ret->ai_addrlen = addrlen;
+	ret->ai_addr = (void*)( ret + 1 );
+	ret->ai_canonname = 0;
+	ret->ai_next = 0;
+	switch(af)
+	{
+	case AF_INET:
+		((struct sockaddr_in*)ret->ai_addr)->sin_family = AF_INET;
+		((struct sockaddr_in*)ret->ai_addr)->sin_port = 0;
+		memcpy( &((struct sockaddr_in*)ret->ai_addr)->sin_addr, addrdata, 4 );
+		break;
+	case AF_INET6:
+		((struct sockaddr_in6*)ret->ai_addr)->sin6_family = AF_INET6;
+		((struct sockaddr_in6*)ret->ai_addr)->sin6_port = 0;
+		memcpy( &((struct sockaddr_in6*)ret->ai_addr)->sin6_addr, addrdata, 16 );
+		break;
+	default:
+		_SysDebug("int_new_addrinfo: BUGCHECK - Unhandled AF %i", af);
+		return NULL;
+	}
+	return ret;
+}
+
+// Callback for getaddrinfo's call to Net_Lookup_Addrs
+int int_getaddinfo_lookupcb(void *info_v, int addr_type, const void *addr)
+{
+	struct sLookupInfo *info = info_v;
+	struct addrinfo	*ent;
+	switch( addr_type )
+	{
+	case NET_ADDRTYPE_IPV4:
+		ent = int_new_addrinfo(AF_INET, addr);
+		break;
+	case NET_ADDRTYPE_IPV6:
+		ent = int_new_addrinfo(AF_INET6, addr);
+		break;
+	default:
+		// Huh... unknown address type, just ignore it
+		return 0;
+	}
+	ent->ai_next = *info->ret_p;
+	*info->ret_p = ent;
+	return 0;
+}
+
 void freeaddrinfo(struct addrinfo *res)
 {
-	
+	while( res )
+	{
+		struct addrinfo *next = res->ai_next;
+		free(res);
+		res = next;
+	}
 }
 
 int getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags)