[sudo-workers] [patch] IPv6 support

Karel Zak kzak at redhat.com
Sun Jul 16 19:11:52 EDT 2006


 Hi guys,

 IPv6 is not so hot news, but the bad thing is that sudo doesn't
 support it. This patch tries implement IPv6 support for sudo.  This
 patch should be checked by some who is really familiar with sudo
 code, because changes are not so trivial.

 Note:  the original author of the patch is Milan Zazrivec
 <mzazrive at redhat.com>. I've reviewed and fix minor things in the
 patch only.

    Karel



--- sudo-1.6.8p12/visudo.c.ipv6	2004-11-25 18:32:40.000000000 +0100
+++ sudo-1.6.8p12/visudo.c	2006-07-17 01:09:53.000000000 +0200
@@ -87,6 +87,7 @@
 static int check_syntax		__P((int));
 int command_matches		__P((char *, char *));
 int addr_matches		__P((char *));
+int addr6_matches		__P((char *));
 int hostname_matches		__P((char *, char *, char *));
 int netgr_matches		__P((char *, char *, char *, char *));
 int usergr_matches		__P((char *, char *, struct passwd *));
@@ -515,6 +516,12 @@
     return(TRUE);
 }
 
+int addr6_matches(n)
+    char *n;
+{
+    return(TRUE);
+}
+
 int
 hostname_matches(s, l, p)
     char *s, *l, *p;
--- sudo-1.6.8p12/parse.lex.ipv6	2004-05-17 22:51:13.000000000 +0200
+++ sudo-1.6.8p12/parse.lex	2006-07-17 01:09:53.000000000 +0200
@@ -84,6 +84,29 @@
 
 OCTET			(1?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5])
 DOTTEDQUAD		{OCTET}(\.{OCTET}){3}
+
+IPV6_8HEX               ([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}
+
+IPV6_COMP0              :(:[0-9A-Fa-f]{1,4}){1,7}
+IPV6_COMP1              ([0-9A-Fa-f]{1,4}){1}:(:[0-9A-Fa-f]{1,4}){0,6}
+IPV6_COMP2              ([0-9A-Fa-f]{1,4}){2}:(:[0-9A-Fa-f]{1,4}){0,5}
+IPV6_COMP3              ([0-9A-Fa-f]{1,4}){3}:(:[0-9A-Fa-f]{1,4}){0,4}
+IPV6_COMP4		([0-9A-Fa-f]{1,4}){4}:(:[0-9A-Fa-f]{1,4}){0,3}
+IPV6_COMP5              ([0-9A-Fa-f]{1,4}){5}:(:[0-9A-Fa-f]{1,4}){0,2}
+IPV6_COMP6              ([0-9A-Fa-f]{1,4}){6}:(:[0-9A-Fa-f]{1,4}){0,1}
+IPV6_COMPHEX            {IPV6_COMP0}|{IPV6_COMP1}|{IPV6_COMP2}|{IPV6_COMP3}|{IPV6_COMP4}|{IPV6_COMP5}|{IPV6_COMP6}
+
+IPV6_6H4D               [0-9A-Fa-f]{1,4}(:[0-9A-Fa-f]{1,4}){5}{DOTTEDQUAD}
+
+IPV6_COMP6H4D0          ([0-9A-Fa-f]{1,4}){1}:(:[0-9A-Fa-f]{1,4}){1,4}:{DOTTEDQUAD}
+IPV6_COMP6H4D1          ([0-9A-Fa-f]{1,4}){2}:(:[0-9A-Fa-f]{1,4}){1,3}:{DOTTEDQUAD}
+IPV6_COMP6H4D2          ([0-9A-Fa-f]{1,4}){3}:(:[0-9A-Fa-f]{1,4}){1,2}:{DOTTEDQUAD}
+IPV6_COMP6H4D3          ([0-9A-Fa-f]{1,4}){4}:(:[0-9A-Fa-f]{1,4}){1}:{DOTTEDQUAD}
+IPV6_COMP6H4D           {IPV6_COMP6H4D0}|{IPV6_COMP6H4D1}|{IPV6_COMP6H4D2}|{IPV6_COMP6H4D3}
+
+IPV6ADDR                {IPV6_8HEX}|{IPV6_COMPHEX}|{IPV6_6H4D}|{IPV6_COMP6H4D}
+IPV6PREFIX		[1-9]|[1-9][0-9]|10[0-9]|11[0-9]|12[0-8]
+
 HOSTNAME		[[:alnum:]_-]+
 WORD			([^#>@!=:,\(\) \t\n\\]|\\[^\n])+
 ENVAR			([^#!=, \t\n\\]|\\[^\n])([^#=, \t\n\\]|\\[^\n])*
@@ -253,6 +276,11 @@
 			    LEXTRACE("NTWKADDR ");
 			    return(NTWKADDR);
 			}
+{IPV6ADDR}(\/{IPV6PREFIX})? {
+			    fill(yytext, yyleng);
+                            LEXTRACE("NTWKADDR6 ");
+                            return(NTWKADDR6);
+			}
 
 <INITIAL>\(		{
 				BEGIN GOTRUNAS;
--- sudo-1.6.8p12/ldap.c.ipv6	2005-06-19 23:31:51.000000000 +0200
+++ sudo-1.6.8p12/ldap.c	2006-07-17 01:09:53.000000000 +0200
@@ -160,6 +160,7 @@
     if (
          !strcasecmp(*p,"ALL") ||
          addr_matches(*p) ||
+         addr6_matches(*p) ||
          netgr_matches(*p,user_host,user_shost,NULL) ||
          !hostname_matches(user_shost,user_host,*p)
        )
--- sudo-1.6.8p12/parse.h.ipv6	2005-06-19 20:58:19.000000000 +0200
+++ sudo-1.6.8p12/parse.h	2006-07-17 01:09:53.000000000 +0200
@@ -93,6 +93,7 @@
  * Prototypes
  */
 int addr_matches	__P((char *));
+int addr6_matches	__P((char *));
 int command_matches	__P((char *, char *));
 int hostname_matches	__P((char *, char *, char *));
 int netgr_matches	__P((char *, char *, char *, char *));
--- sudo-1.6.8p12/interfaces.h.ipv6	2004-02-13 22:36:43.000000000 +0100
+++ sudo-1.6.8p12/interfaces.h	2006-07-17 01:09:53.000000000 +0200
@@ -27,8 +27,11 @@
  * IP address and netmask pairs for checking against local interfaces.
  */
 struct interface {
-    struct in_addr addr;
+    struct in_addr addr;	/* IPv4 */
     struct in_addr netmask;
+    struct in6_addr addr6;	/* IPv6 */
+    struct in6_addr netmask6;
+    sa_family_t sa_family;	/* AF_INET ? AF_INET6 */
 };
 
 /*
--- sudo-1.6.8p12/parse.c.ipv6	2005-06-19 22:03:24.000000000 +0200
+++ sudo-1.6.8p12/parse.c	2006-07-17 01:09:53.000000000 +0200
@@ -370,38 +370,134 @@
     int i;
     char *m;
     struct in_addr addr, mask;
+    struct addrinfo hints, *ai;
+
+    memset(&hints, '\0', sizeof(hints));
+    hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST;
+    hints.ai_family = AF_INET;
 
     /* If there's an explicit netmask, use it. */
     if ((m = strchr(n, '/'))) {
+
 	*m++ = '\0';
-	addr.s_addr = inet_addr(n);
+	if (getaddrinfo(n, NULL, &hints, &ai)!=0)
+	    return(FALSE);
+	memcpy(&addr.s_addr, &((struct sockaddr_in *)ai->ai_addr)->sin_addr,
+		  sizeof(struct in_addr));
+	freeaddrinfo(ai);
+
 	if (strchr(m, '.'))
-	    mask.s_addr = inet_addr(m);
-	else {
-	    i = 32 - atoi(m);
-	    mask.s_addr = 0xffffffff;
-	    mask.s_addr >>= i;
-	    mask.s_addr <<= i;
-	    mask.s_addr = htonl(mask.s_addr);
+	{
+	    if (getaddrinfo(m, NULL, &hints, &ai)!=0)
+		return(FALSE);
+	    memcpy(&mask.s_addr,    /* IPv4 netmask from dotted quad */
+			&((struct sockaddr_in *)ai->ai_addr)->sin_addr,
+			sizeof(struct in_addr));
 	}
+       	else
+       	{
+       	    i = 32 - atoi(m);	/* IPv4 netmask from CIDR */
+       	    mask.s_addr = 0xffffffff;
+       	    mask.s_addr >>= i;
+            mask.s_addr <<= i;
+       	    mask.s_addr = htonl(mask.s_addr);
+       	}
+
 	*(m - 1) = '/';
 
-	for (i = 0; i < num_interfaces; i++)
-	    if ((interfaces[i].addr.s_addr & mask.s_addr) == addr.s_addr)
-		return(TRUE);
+	for (i = 0; i <  num_interfaces; ++i)
+	    if (interfaces[i].sa_family == AF_INET)	/* IPv4 intf. only */
+		if ((interfaces[i].addr.s_addr & mask.s_addr) == addr.s_addr)
+		    return (TRUE);
     } else {
-	addr.s_addr = inet_addr(n);
+	if (getaddrinfo(n, NULL, &hints, &ai)!=0)
+	    return(FALSE);
+        memcpy(&addr.s_addr, &((struct sockaddr_in *)ai->ai_addr)->sin_addr,
+                  sizeof(struct in_addr));
+	freeaddrinfo(ai);
 
 	for (i = 0; i < num_interfaces; i++)
-	    if (interfaces[i].addr.s_addr == addr.s_addr ||
-		(interfaces[i].addr.s_addr & interfaces[i].netmask.s_addr)
-		== addr.s_addr)
-		return(TRUE);
+	    if (interfaces[i].sa_family == AF_INET)     /* IPv4 intf. only */
+	        if (interfaces[i].addr.s_addr == addr.s_addr ||
+	            (interfaces[i].addr.s_addr & interfaces[i].netmask.s_addr)
+			 == addr.s_addr)
+		    return(TRUE);
     }
 
     return(FALSE);
 }
 
+int
+addr6_matches(n)
+char *n;
+{
+    int i, j;
+    uint32_t msk[4] = {0, 0, 0, 0};	/* 32x4 */
+    uint32_t addr[4], i_msk[4], i_addr[4];
+    char *m;
+    struct addrinfo hints, *ai;
+
+    memset(&hints, '\0', sizeof(hints));
+    hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST;
+    hints.ai_family = AF_INET6;
+	
+    /* we have IPv6 prefix */
+    if ((m = strchr(n, '/'))) {
+	*m++ = '\0';
+	if (getaddrinfo(n, NULL, &hints, &ai)!=0)
+            return(FALSE);
+	memcpy(&addr, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr, 16);
+	freeaddrinfo(ai);
+
+	for (i=0; i < (atoi(m)/32); ++i)
+	    msk[i] = 0xffffffff;
+	if (atoi(m)<128 && (atoi(m) % 32))
+	{
+	    msk[atoi(m)/32] = 0xffffffff;
+	    msk[atoi(m)/32] >>= ( 32 - (atoi(m) % 32) );
+	    msk[atoi(m)/32] <<= ( 32 - (atoi(m) % 32) );
+	}
+	for (i=0; i<4; ++i)
+	    msk[i] = htonl(msk[i]);
+	
+	*(m - 1) = '/';
+	
+	for (i=0; i < num_interfaces; i++)
+	    if (interfaces[i].sa_family == AF_INET6)	/* compare only IPv6 intf. */
+	    {
+		/* nasty */
+	        memcpy(&i_addr, &interfaces[i].addr6, 16);
+		if ( ((i_addr[0] & msk[0]) == addr[0]) &&
+		     ((i_addr[1] & msk[1]) == addr[1]) &&
+		     ((i_addr[2] & msk[2]) == addr[2]) &&
+		     ((i_addr[3] & msk[3]) == addr[3]))
+		    return(TRUE);
+	    }	     
+    } else {
+        if (getaddrinfo(n, NULL, &hints, &ai)!=0)
+	    return(FALSE);
+        memcpy(&addr, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr, 16);
+        freeaddrinfo(ai);
+
+	for (i=0; i < num_interfaces; ++i)
+	    if (interfaces[i].sa_family == AF_INET6) /* IPv6 intf. only */
+	    {
+	        memcpy(&i_addr, &interfaces[i].addr6, 16);
+		if ((i_addr[0] == addr[0]) && (i_addr[1] == addr[1]) &&
+		    (i_addr[2] == addr[2]) && (i_addr[3] == addr[3]))
+		    return(TRUE); /* found my own address in sudoers */
+
+		memcpy(&i_msk, &interfaces[i].netmask6, 16);
+		if (((i_addr[0]&i_msk[0]) == addr[0]) &&
+		    ((i_addr[1]&i_msk[1]) == addr[1]) &&
+		    ((i_addr[2]&i_msk[2]) == addr[2]) &&
+		    ((i_addr[3]&i_msk[3]) == addr[3]))
+		    return(TRUE); /* found my netw. address in sudoers */
+	    }
+    }
+    return(FALSE);
+}
+
 /*
  * Returns 0 if the hostname matches the pattern and non-zero otherwise.
  */
--- sudo-1.6.8p12/sudo.c.ipv6	2006-07-17 01:09:53.000000000 +0200
+++ sudo-1.6.8p12/sudo.c	2006-07-17 01:09:53.000000000 +0200
@@ -1007,24 +1007,34 @@
 void
 set_fqdn()
 {
-    struct hostent *hp;
+    struct addrinfo hints, *ai;
     char *p;
 
-    if (!(hp = gethostbyname(user_host))) {
-	log_error(MSG_ONLY|NO_EXIT,
-	    "unable to lookup %s via gethostbyname()", user_host);
-    } else {
-	if (user_shost != user_host)
+    memset(&hints, '\0', sizeof(hints));
+    hints.ai_flags = AI_ADDRCONFIG;
+    
+    if (getaddrinfo(user_host, NULL, &hints, &ai) != 0)
+    {
+        log_error(MSG_ONLY|NO_EXIT,
+		"unable to lookup %s via gethostbyname()", user_host);
+    }
+    else
+    {
+	char h_name[NI_MAXHOST];
+
+        if (user_host != user_host)
 	    free(user_shost);
+
+	getnameinfo(ai->ai_addr, ai->ai_addrlen, h_name, sizeof(h_name), NULL, 0, 0);
 	free(user_host);
-	user_host = estrdup(hp->h_name);
+	user_host = estrdup(h_name);
     }
     if ((p = strchr(user_host, '.'))) {
-	*p = '\0';
-	user_shost = estrdup(user_host);
-	*p = '.';
+        *p = '\0';
+        user_shost = estrdup(user_host);
+        *p = '.';
     } else {
-	user_shost = user_host;
+        user_shost = user_host;
     }
 }
 
--- sudo-1.6.8p12/parse.yacc.ipv6	2005-06-19 20:24:32.000000000 +0200
+++ sudo-1.6.8p12/parse.yacc	2006-07-17 01:09:53.000000000 +0200
@@ -250,6 +250,7 @@
 %token <tok>	 RUNASALIAS		/* Runas_Alias keyword */
 %token <tok>	 ':' '=' ',' '!' '+' '-' /* union member tokens */
 %token <tok>	 ERROR
+%token <string>  NTWKADDR6		/* IPv6 address */
 
 /*
  * NOTE: these are not true booleans as there are actually 4 possible values:
@@ -395,6 +396,13 @@
 				$$ = NOMATCH;
 			    free($1);
 			}
+		|	NTWKADDR6 {
+			    if (addr6_matches($1))
+				$$ = TRUE;
+			    else
+				$$ = NOMATCH;
+			    free($1);
+			}
 		|	NETGROUP {
 			    if (netgr_matches($1, user_host, user_shost, NULL))
 				$$ = TRUE;
--- sudo-1.6.8p12/testsudoers.c.ipv6	2004-08-02 20:44:58.000000000 +0200
+++ sudo-1.6.8p12/testsudoers.c	2006-07-17 01:09:53.000000000 +0200
@@ -175,6 +175,10 @@
     }
 }
 
+/*
+ * Returns TRUE if "n" is one of our ip addresses or if
+ * "n" is a network that we are on, else returns FALSE.
+ */
 int
 addr_matches(n)
     char *n;
@@ -182,39 +186,136 @@
     int i;
     char *m;
     struct in_addr addr, mask;
+    struct addrinfo hints, *ai;
+
+    memset(&hints, '\0', sizeof(hints));
+    hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST;
+    hints.ai_family = AF_INET;
 
     /* If there's an explicit netmask, use it. */
     if ((m = strchr(n, '/'))) {
-	*m++ = '\0';
-	addr.s_addr = inet_addr(n);
-	if (strchr(m, '.'))
-	    mask.s_addr = inet_addr(m);
-	else {
-	    i = 32 - atoi(m);
-	    mask.s_addr = 0xffffffff;
-	    mask.s_addr >>= i;
-	    mask.s_addr <<= i;
-	    mask.s_addr = htonl(mask.s_addr);
-	}
-	*(m - 1) = '/';
 
-	for (i = 0; i < num_interfaces; i++)
-	    if ((interfaces[i].addr.s_addr & mask.s_addr) == addr.s_addr)
-		return(TRUE);
+        *m++ = '\0';
+        if (getaddrinfo(n, NULL, &hints, &ai)!=0)
+	    return(FALSE);
+        memcpy(&addr.s_addr, &((struct sockaddr_in *)ai->ai_addr)->sin_addr,
+                  sizeof(struct in_addr));
+        freeaddrinfo(ai);
+
+        if (strchr(m, '.'))
+        {
+            if (getaddrinfo(m, NULL, &hints, &ai)!=0)
+		return(FALSE);
+            memcpy(&mask.s_addr,    /* IPv4 netmask from dotted quad */
+                        &((struct sockaddr_in *)ai->ai_addr)->sin_addr,
+                        sizeof(struct in_addr));
+        }
+        else
+        {
+            i = 32 - atoi(m);   /* IPv4 netmask from CIDR */
+            mask.s_addr = 0xffffffff;
+            mask.s_addr >>= i;
+            mask.s_addr <<= i;
+            mask.s_addr = htonl(mask.s_addr);
+        }
+
+        *(m - 1) = '/';
+
+        for (i = 0; i <  num_interfaces; ++i)
+            if (interfaces[i].sa_family == AF_INET)     /* IPv4 intf. only */
+                if ((interfaces[i].addr.s_addr & mask.s_addr) == addr.s_addr)
+                    return(TRUE);
     } else {
-	addr.s_addr = inet_addr(n);
-
-	for (i = 0; i < num_interfaces; i++)
-	    if (interfaces[i].addr.s_addr == addr.s_addr ||
-		(interfaces[i].addr.s_addr & interfaces[i].netmask.s_addr)
-		== addr.s_addr)
-		return(TRUE);
+        if (getaddrinfo(n, NULL, &hints, &ai)!=0)
+	    return(FALSE);
+        memcpy(&addr.s_addr, &((struct sockaddr_in *)ai->ai_addr)->sin_addr,
+                  sizeof(struct in_addr));
+        freeaddrinfo(ai);
+
+        for (i = 0; i < num_interfaces; i++)
+            if (interfaces[i].sa_family == AF_INET)     /* IPv4 intf. only */
+                if (interfaces[i].addr.s_addr == addr.s_addr ||
+                    (interfaces[i].addr.s_addr & interfaces[i].netmask.s_addr)
+                         == addr.s_addr)
+                    return(TRUE);
     }
 
     return(FALSE);
 }
 
 int
+addr6_matches(n)
+char *n;
+{
+    int i, j;
+    uint32_t msk[4] = {0, 0, 0, 0};     /* 32x4 */
+    uint32_t addr[4], i_msk[4], i_addr[4];
+    char *m;
+    struct addrinfo hints, *ai;
+
+    memset(&hints, '\0', sizeof(hints));
+    hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST;
+    hints.ai_family = AF_INET6;
+
+    /* we have IPv6 prefix */
+    if ((m = strchr(n, '/'))) {
+        *m++ = '\0';
+        if (getaddrinfo(n, NULL, &hints, &ai)!=0)
+	    return(FALSE);
+        memcpy(&addr, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr, 16);
+        freeaddrinfo(ai);
+
+        for (i=0; i < (atoi(m)/32); ++i)
+            msk[i] = 0xffffffff;
+        if (atoi(m)<128 && (atoi(m) % 32))
+        {
+            msk[atoi(m)/32] = 0xffffffff;
+            msk[atoi(m)/32] >>= ( 32 - (atoi(m) % 32) );
+            msk[atoi(m)/32] <<= ( 32 - (atoi(m) % 32) );
+        }
+        for (i=0; i<4; ++i)
+            msk[i] = htonl(msk[i]);
+
+        *(m - 1) = '/';
+
+        for (i=0; i < num_interfaces; i++)
+            if (interfaces[i].sa_family == AF_INET6)    /* compare only IPv6 intf. */
+            {
+                /* nasty */
+                memcpy(&i_addr, &interfaces[i].addr6, 16);
+                if ( ((i_addr[0] & msk[0]) == addr[0]) &&
+                     ((i_addr[1] & msk[1]) == addr[1]) &&
+                     ((i_addr[2] & msk[2]) == addr[2]) &&
+                     ((i_addr[3] & msk[3]) == addr[3]))
+                    return (TRUE);
+            }
+    } else {
+        if (getaddrinfo(n, NULL, &hints, &ai)!=0)
+	    return(FALSE);
+        memcpy(&addr, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr, 16);
+        freeaddrinfo(ai);
+
+        for (i=0; i < num_interfaces; ++i)
+            if (interfaces[i].sa_family == AF_INET6) /* IPv6 intf. only */
+            {
+                memcpy(&i_addr, &interfaces[i].addr6, 16);
+                if ((i_addr[0] == addr[0]) && (i_addr[1] == addr[1]) &&
+                    (i_addr[2] == addr[2]) && (i_addr[3] == addr[3]))
+                    return (TRUE); /* found my own address in sudoers */
+
+                memcpy(&i_msk, &interfaces[i].netmask6, 16);
+                if (((i_addr[0]&i_msk[0]) == addr[0]) &&
+                    ((i_addr[1]&i_msk[1]) == addr[1]) &&
+                    ((i_addr[2]&i_msk[2]) == addr[2]) &&
+                    ((i_addr[3]&i_msk[3]) == addr[3]))
+                    return (TRUE); /* found my netw. address in sudoers */
+            }
+    }
+    return(FALSE);
+}
+
+
+int
 hostname_matches(shost, lhost, pattern)
     char *shost;
     char *lhost;
--- sudo-1.6.8p12/interfaces.c.ipv6	2004-02-13 22:36:43.000000000 +0100
+++ sudo-1.6.8p12/interfaces.c	2006-07-17 01:09:53.000000000 +0200
@@ -102,7 +102,7 @@
 load_interfaces()
 {
     struct ifaddrs *ifa, *ifaddrs;
-    /* XXX - sockaddr_in6 sin6; */
+    struct sockaddr_in6 *sin6;
     struct sockaddr_in *sin;
     int i;
 
@@ -117,12 +117,15 @@
 	    continue;
 
 	switch(ifa->ifa_addr->sa_family) {
-	    /* XXX - AF_INET6 */
 	    case AF_INET:
 		num_interfaces++;
 		break;
+	    case AF_INET6:
+		num_interfaces++;
+		break;
 	}
     }
+
     if (num_interfaces == 0)
 	return;
     interfaces =
@@ -136,8 +139,8 @@
 		continue;
 
 	switch(ifa->ifa_addr->sa_family) {
-	    /* XXX - AF_INET6 */
 	    case AF_INET:
+		interfaces[i].sa_family = AF_INET;
 		sin = (struct sockaddr_in *)ifa->ifa_addr;
 		memcpy(&interfaces[i].addr, &sin->sin_addr,
 		    sizeof(struct in_addr));
@@ -146,6 +149,16 @@
 		    sizeof(struct in_addr));
 		i++;
 		break;
+	    case AF_INET6:
+		interfaces[i].sa_family = AF_INET6;
+		sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
+		memcpy(&interfaces[i].addr6, &sin6->sin6_addr,
+		    sizeof(struct in6_addr));
+		sin6 = (struct sockaddr_in6 *)ifa->ifa_netmask;
+                memcpy(&interfaces[i].netmask6, &sin6->sin6_addr,
+                    sizeof(struct in6_addr));	
+		i++;
+		break;
 	}
     }
 #ifdef HAVE_FREEIFADDRS
@@ -306,10 +319,30 @@
 void
 dump_interfaces()
 {
-    int i;
+    int i, j, ip6_prefix=0; 	/* for counting IPv6 prefix length (in bits!!) */
+    uint8_t u6_addr8[16]; 	/* for storing IPv6 netmask */
 
     puts("Local IP address and netmask pairs:");
     for (i = 0; i < num_interfaces; i++)
-	printf("\t%s / 0x%x\n", inet_ntoa(interfaces[i].addr),
-	    (unsigned int)ntohl(interfaces[i].netmask.s_addr));
+    {
+	char name[NI_MAXHOST], netmask[NI_MAXHOST];
+	ip6_prefix=0;
+	
+	switch (interfaces[i].sa_family)
+	{
+	    case AF_INET:
+		inet_ntop(AF_INET, &interfaces[i].addr, name, NI_MAXHOST);
+		inet_ntop(AF_INET, &interfaces[i].netmask, netmask, NI_MAXHOST);
+		printf("\t%s / %s\n", name, netmask);
+		break;
+	    case AF_INET6:
+		inet_ntop(AF_INET6, &interfaces[i].addr6, name, NI_MAXHOST);
+		memcpy(u6_addr8, &interfaces[i].netmask6, 16);
+		for (j=0; j<16; ++j) 
+		    if (u6_addr8[j] == 255)		/* 255 == 0xff */
+			 ip6_prefix=ip6_prefix+8;	/* eight bits */
+		printf("\t%s / %d\n", name, ip6_prefix);
+		break;
+	}
+    }
 }



More information about the sudo-workers mailing list