Control: tag -1 patch

Hi,

On Thu, May 02, 2013 at 02:36:53PM +0200, Joachim Breitner wrote:
> thanks, looking forward to it.

the patches are attached.

Kind regards
Philipp Kern
From ea73addba30102219b7d66b9ce0735e451957e5a Mon Sep 17 00:00:00 2001
From: Philipp Kern <pk...@debian.org>
Date: Wed, 1 May 2013 01:30:32 +0200
Subject: [PATCH 1/4] Change the control flow of _nss_gw_name_gethostbyname_r.

If the name to be resolved is not gateway.localhost, we can bail out
directly. If the buffer space is not sufficient to store the result,
we do not need to determine the default gateway at all. Restructure
the function to make this clearer.
---
 libnss_gw_name.c |   97 +++++++++++++++++++++++++++---------------------------
 1 file changed, 48 insertions(+), 49 deletions(-)

diff --git a/libnss_gw_name.c b/libnss_gw_name.c
index 49780f6..8f8d57c 100644
--- a/libnss_gw_name.c
+++ b/libnss_gw_name.c
@@ -109,60 +109,59 @@ enum nss_status _nss_gw_name_gethostbyname_r (
 	size_t idx, astart;
 	struct nl_addr *gw;
 
-	if (!strcmp(name,"gateway.localhost")) {
-		// Look up gatway
-		gw = find_gateway();
-		if (!gw) {
-			*errnop = EAGAIN;
-			*h_errnop = NO_RECOVERY;
-			return NSS_STATUS_TRYAGAIN;
-		}
-
-		if (buflen <
-			sizeof(char*)+    /* alias names */
-			strlen(name)+1+   /* main name */
-			sizeof(ipv4_address_t)+ /* address */
-			sizeof(char*)+ /* null address pointer */
-			8 /* Alignment */
-			)  {   /* official name */
-
-			nl_addr_put(gw);
-
-			*errnop = ERANGE;
-			*h_errnop = NO_RECOVERY;
-			return NSS_STATUS_TRYAGAIN;
-		}
-	
-
-		/* Alias names */
-		*((char**) buffer) = NULL;
-		result->h_aliases = (char**) buffer;
-		idx = sizeof(char*);
-
-		/* Official name */
-		strcpy(buffer+idx, name); 
-		result->h_name = buffer+idx;
-		idx += strlen(name)+1;
-		ALIGN(idx);
+	// We only resolve exactly one name
+	if (strcmp(name,"gateway.localhost")) {
+		*errnop = EINVAL;
+		*h_errnop = NO_RECOVERY;
+		return NSS_STATUS_UNAVAIL;
+	}
 
-		result->h_addrtype = AF_INET;
-		result->h_length = sizeof(ipv4_address_t);
+	// Check if enough buffer space is available at the target location
+	if (buflen <
+		sizeof(char*)+    /* alias names */
+		strlen(name)+1+   /* main name */
+		sizeof(ipv4_address_t)+ /* address */
+		sizeof(char*)+ /* null address pointer */
+		8 /* Alignment */
+		)  {   /* official name */
 
-		astart = idx;
-		memcpy(buffer+astart, nl_addr_get_binary_addr(gw), sizeof(ipv4_address_t));
-		idx += sizeof(ipv4_address_t);
-		
-		result->h_addr_list = (char**)(buffer + idx);
-		result->h_addr_list[0] = buffer + astart;
-		result->h_addr_list[1] = NULL;
+		*errnop = ERANGE;
+		*h_errnop = NO_RECOVERY;
+		return NSS_STATUS_TRYAGAIN;
+	}
 
-		nl_addr_put(gw);
-		return NSS_STATUS_SUCCESS;
-	}{
-		*errnop = EINVAL;
+	// Look up gateway
+	gw = find_gateway();
+	if (!gw) {
+		*errnop = EAGAIN;
 		*h_errnop = NO_RECOVERY;
-		return NSS_STATUS_UNAVAIL;
+		return NSS_STATUS_TRYAGAIN;
 	}
+
+	/* Alias names */
+	*((char**) buffer) = NULL;
+	result->h_aliases = (char**) buffer;
+	idx = sizeof(char*);
+
+	/* Official name */
+	strcpy(buffer+idx, name); 
+	result->h_name = buffer+idx;
+	idx += strlen(name)+1;
+	ALIGN(idx);
+
+	result->h_addrtype = AF_INET;
+	result->h_length = sizeof(ipv4_address_t);
+
+	astart = idx;
+	memcpy(buffer+astart, nl_addr_get_binary_addr(gw), sizeof(ipv4_address_t));
+	idx += sizeof(ipv4_address_t);
+	
+	result->h_addr_list = (char**)(buffer + idx);
+	result->h_addr_list[0] = buffer + astart;
+	result->h_addr_list[1] = NULL;
+
+	nl_addr_put(gw);
+	return NSS_STATUS_SUCCESS;
 }
 
 enum nss_status _nss_gw_name_gethostbyname2_r(
-- 
1.7.10.4

From c947d2fefc816647161701ef81b523b4c32378c7 Mon Sep 17 00:00:00 2001
From: Philipp Kern <pk...@debian.org>
Date: Wed, 1 May 2013 01:39:41 +0200
Subject: [PATCH 2/4] Make find_gateway address family-aware.

The netlink interfaces allows to query for different families. Simply
make the address family a parameter of the function.
---
 libnss_gw_name.c |   10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/libnss_gw_name.c b/libnss_gw_name.c
index 8f8d57c..573a121 100644
--- a/libnss_gw_name.c
+++ b/libnss_gw_name.c
@@ -38,7 +38,7 @@ typedef struct {
 
 
 static struct nl_addr *
-find_gateway() {
+find_gateway(int family) {
 	struct nl_cache* route_cache;
 	struct nl_sock *sock;
 	struct nl_object *obj;
@@ -54,7 +54,7 @@ find_gateway() {
 		return NULL;
 	}
 
-	if (rtnl_route_alloc_cache(sock, AF_INET, 0, &route_cache)) {
+	if (rtnl_route_alloc_cache(sock, family, 0, &route_cache)) {
 		nl_close(sock);
 		nl_socket_free(sock);
 		return NULL;
@@ -63,8 +63,8 @@ find_gateway() {
 	for (obj = nl_cache_get_first(route_cache); obj; obj = nl_cache_get_next(obj)) {
 		struct rtnl_route *route = (struct rtnl_route *)obj;
 
-		// Ignore non ipv4 routes
-		if (rtnl_route_get_family(route) != AF_INET) continue;
+		// Ignore routes not matching the current family
+		if (rtnl_route_get_family(route) != family) continue;
 
 		// Find a default route
 		if (nl_addr_get_prefixlen(rtnl_route_get_dst(route)) != 0) continue;
@@ -131,7 +131,7 @@ enum nss_status _nss_gw_name_gethostbyname_r (
 	}
 
 	// Look up gateway
-	gw = find_gateway();
+	gw = find_gateway(AF_INET);
 	if (!gw) {
 		*errnop = EAGAIN;
 		*h_errnop = NO_RECOVERY;
-- 
1.7.10.4

From 2243eb1d9c72e27296118532f2760b1ed615f59c Mon Sep 17 00:00:00 2001
From: Philipp Kern <pk...@debian.org>
Date: Wed, 1 May 2013 01:40:27 +0200
Subject: [PATCH 3/4] Put the network address length into a variable.

For IPv6 support the address length will be different. Use a variable
instead of hardcoded sizeofs of a single typedef.
---
 libnss_gw_name.c |   16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/libnss_gw_name.c b/libnss_gw_name.c
index 573a121..9c38300 100644
--- a/libnss_gw_name.c
+++ b/libnss_gw_name.c
@@ -26,9 +26,7 @@
 #include <errno.h>
 #include <sys/socket.h>
 
-typedef struct {
-    uint32_t address;
-} ipv4_address_t;
+typedef uint32_t ipv4_address_t;
 
 
 #define ALIGN(idx) do { \
@@ -106,7 +104,7 @@ enum nss_status _nss_gw_name_gethostbyname_r (
 	int *errnop,
 	int *h_errnop) {
 
-	size_t idx, astart;
+	size_t idx, astart, alength;
 	struct nl_addr *gw;
 
 	// We only resolve exactly one name
@@ -116,11 +114,13 @@ enum nss_status _nss_gw_name_gethostbyname_r (
 		return NSS_STATUS_UNAVAIL;
 	}
 
+	alength = sizeof(ipv4_address_t);
+
 	// Check if enough buffer space is available at the target location
 	if (buflen <
 		sizeof(char*)+    /* alias names */
 		strlen(name)+1+   /* main name */
-		sizeof(ipv4_address_t)+ /* address */
+		alength+          /* address */
 		sizeof(char*)+ /* null address pointer */
 		8 /* Alignment */
 		)  {   /* official name */
@@ -150,11 +150,11 @@ enum nss_status _nss_gw_name_gethostbyname_r (
 	ALIGN(idx);
 
 	result->h_addrtype = AF_INET;
-	result->h_length = sizeof(ipv4_address_t);
+	result->h_length = alength;
 
 	astart = idx;
-	memcpy(buffer+astart, nl_addr_get_binary_addr(gw), sizeof(ipv4_address_t));
-	idx += sizeof(ipv4_address_t);
+	memcpy(buffer+astart, nl_addr_get_binary_addr(gw), alength);
+	idx += alength;
 	
 	result->h_addr_list = (char**)(buffer + idx);
 	result->h_addr_list[0] = buffer + astart;
-- 
1.7.10.4

From f7503c7fc9b55540797f4a01adbd5c98040781b5 Mon Sep 17 00:00:00 2001
From: Philipp Kern <pk...@debian.org>
Date: Wed, 1 May 2013 01:55:07 +0200
Subject: [PATCH 4/4] Add support for IPv6.

There are two ways from which a system can learn its default gateway
for IPv6. The most common is through router advertisements. These
are sent by the router and the client, if configured to accept them,
will use the link-local address of the router on the source interface
of the RA as its default gateway. The other way is static configuration,
which can use link-local and global addresses as the next hop target
for the default gateway.

This provides access to the default gateway in the routing table
by adding a IPv6 record to gateway.localhost and by providing two
new records: gateway{4,6}.localhost, which return the record of
their respective address family only.

The NSS API does not allow to return scope identifiers through the
gethostbyname interface. These are needed to associate a link-local
address with the interface they are valid on. This means that you
need to know which interface is used for your connection to use
the IPv6 record for something meaningful. (E.g., you can pass
"-I wlan0" to ping6 when using this information.)
---
 libnss_gw_name.c |   65 +++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 45 insertions(+), 20 deletions(-)

diff --git a/libnss_gw_name.c b/libnss_gw_name.c
index 9c38300..59a4cfb 100644
--- a/libnss_gw_name.c
+++ b/libnss_gw_name.c
@@ -96,7 +96,8 @@ find_gateway(int family) {
 	return gw;
 }
 
-enum nss_status _nss_gw_name_gethostbyname_r (
+enum nss_status _nss_gw_name_gethostbyname_r_internal (
+	int af,
 	const char *name,
 	struct hostent *result,
 	char *buffer,
@@ -107,14 +108,14 @@ enum nss_status _nss_gw_name_gethostbyname_r (
 	size_t idx, astart, alength;
 	struct nl_addr *gw;
 
-	// We only resolve exactly one name
-	if (strcmp(name,"gateway.localhost")) {
-		*errnop = EINVAL;
-		*h_errnop = NO_RECOVERY;
-		return NSS_STATUS_UNAVAIL;
+	// Look up gateway
+	gw = find_gateway(af);
+	if (!gw) {
+		*errnop = EAGAIN;
+		*h_errnop = NO_ADDRESS;
+		return NSS_STATUS_TRYAGAIN;
 	}
-
-	alength = sizeof(ipv4_address_t);
+	alength = nl_addr_get_len(gw);
 
 	// Check if enough buffer space is available at the target location
 	if (buflen <
@@ -130,14 +131,6 @@ enum nss_status _nss_gw_name_gethostbyname_r (
 		return NSS_STATUS_TRYAGAIN;
 	}
 
-	// Look up gateway
-	gw = find_gateway(AF_INET);
-	if (!gw) {
-		*errnop = EAGAIN;
-		*h_errnop = NO_RECOVERY;
-		return NSS_STATUS_TRYAGAIN;
-	}
-
 	/* Alias names */
 	*((char**) buffer) = NULL;
 	result->h_aliases = (char**) buffer;
@@ -149,7 +142,7 @@ enum nss_status _nss_gw_name_gethostbyname_r (
 	idx += strlen(name)+1;
 	ALIGN(idx);
 
-	result->h_addrtype = AF_INET;
+	result->h_addrtype = af;
 	result->h_length = alength;
 
 	astart = idx;
@@ -164,6 +157,32 @@ enum nss_status _nss_gw_name_gethostbyname_r (
 	return NSS_STATUS_SUCCESS;
 }
 
+enum nss_status _nss_gw_name_gethostbyname_r (
+	const char *name,
+	struct hostent *result,
+	char *buffer,
+	size_t buflen,
+	int *errnop,
+	int *h_errnop) {
+
+	int af;
+
+	// This API function does not allow to return records across address
+	// families. Return the IPv4 version of gateway and use the
+	// corresponding families for gateway4 and gateway6.
+	if (!strcmp(name, "gateway.localhost") || !strcmp(name, "gateway4.localhost")) {
+		af = AF_INET;
+	} else if (!strcmp(name, "gateway6.localhost")) {
+		af = AF_INET6;
+	} else {
+		*errnop = EINVAL;
+		*h_errnop = NO_RECOVERY;
+		return NSS_STATUS_UNAVAIL;
+	}
+
+	return _nss_gw_name_gethostbyname_r_internal(af, name, result, buffer, buflen, errnop, h_errnop);
+}
+
 enum nss_status _nss_gw_name_gethostbyname2_r(
 	const char *name,
 	int af,
@@ -173,12 +192,18 @@ enum nss_status _nss_gw_name_gethostbyname2_r(
 	int *errnop,
 	int *h_errnop) {
 
-	if (af != AF_INET) {
+	// gateway is supported for both IPv4 and IPv6 (and will return both
+	// in ahosts through this function), the other two are IPv4/IPv6-only
+	// respectively.
+	if ((strcmp(name,"gateway.localhost") == 0) || (
+		((af != AF_INET) || strcmp(name, "gateway4.localhost") == 0) &&
+		((af != AF_INET6) || strcmp(name, "gateway6.localhost") == 0))) {
+
+		return _nss_gw_name_gethostbyname_r_internal(af, name, result, buffer, buflen, errnop, h_errnop);
+	} else {
 		*errnop = EAGAIN;
 		*h_errnop = NO_RECOVERY;
 		return NSS_STATUS_TRYAGAIN;
-	} else {
-		return _nss_gw_name_gethostbyname_r(name, result, buffer, buflen, errnop, h_errnop);
 	}
 }
 
-- 
1.7.10.4

Attachment: signature.asc
Description: Digital signature

Reply via email to