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
signature.asc
Description: Digital signature