[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[PATCH] nbd-server: handle auth for v6-mapped IPv4 addresses



This patch adds support for using IPv4 addresses in the nbd-server auth file
even if the socket provides v6-mapped addresses. It extends the comparison
code in address_matches to handle the two cases where the auth file and the
socket use different address families.

This fixes issue #35 in the github repository.

Signed-off-by: Graham R. Cobb <g.nbd@cobb.uk.net>
---
 nbdsrv.c | 30 ++++++++++++++++++++++++------
 1 file changed, 24 insertions(+), 6 deletions(-)

diff --git a/nbdsrv.c b/nbdsrv.c
index 168d425..01ba1b2 100644
--- a/nbdsrv.c
+++ b/nbdsrv.c
@@ -35,6 +35,9 @@ bool address_matches(const char* mask, const struct sockaddr* addr, GError** err
 	char privmask[strlen(mask)+1];
 	int masklen;
 	int addrlen = addr->sa_family == AF_INET ? 4 : 16;
+#define IPV4_MAP_PREFIX 12
+	uint8_t ipv4_mapped[IPV4_MAP_PREFIX+4] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		255, 255, 0, 0, 0, 0};
 
 	strcpy(privmask, mask);
 
@@ -61,12 +64,9 @@ bool address_matches(const char* mask, const struct sockaddr* addr, GError** err
 		uint8_t* byte_t;
 		uint8_t mask = 0;
 		int len_left = masklen;
-		if(res->ai_family != addr->sa_family) {
-			msg(LOG_DEBUG, "client address does not match %d/%d: address family mismatch (IPv4 vs IPv6?)",
-			    (int)res->ai_family, (int)addr->sa_family);
-			goto next;
-		}
-		switch(addr->sa_family) {
+		if(res->ai_family == addr->sa_family) {
+			/* Both addresses are the same address family so do a simple comparison */
+			switch(addr->sa_family) {
 			case AF_INET:
 				byte_s = (const uint8_t*)(&(((struct sockaddr_in*)addr)->sin_addr));
 				byte_t = (uint8_t*)(&(((struct sockaddr_in*)(res->ai_addr))->sin_addr));
@@ -75,6 +75,24 @@ bool address_matches(const char* mask, const struct sockaddr* addr, GError** err
 				byte_s = (const uint8_t*)(&(((struct sockaddr_in6*)addr)->sin6_addr));
 				byte_t = (uint8_t*)(&(((struct sockaddr_in6*)(res->ai_addr))->sin6_addr));
 				break;
+			}
+		} else {
+			/* Addresses are different families, compare IPv4-mapped IPv6 address */
+			switch(addr->sa_family) {
+			case AF_INET:
+				/* Map client address to IPv6 for comparison */
+				memcpy(&ipv4_mapped[IPV4_MAP_PREFIX], &(((struct sockaddr_in*)addr)->sin_addr), 4);
+				byte_s = (const uint8_t*)&ipv4_mapped;
+				byte_t = (uint8_t*)(&(((struct sockaddr_in6*)(res->ai_addr))->sin6_addr));
+				len_left += IPV4_MAP_PREFIX * 8;
+				break;
+			case AF_INET6:
+				byte_s = (const uint8_t*)(&(((struct sockaddr_in6*)addr)->sin6_addr));
+				/* Map res to IPv6 for comparison */
+				memcpy(&ipv4_mapped[IPV4_MAP_PREFIX], &(((struct sockaddr_in*)(res->ai_addr))->sin_addr), 4);
+				byte_t = &ipv4_mapped[0];
+				break;
+			}
 		}
 		while(len_left >= 8) {
 			if(*byte_s != *byte_t) {
-- 
2.29.2


Reply to: