From nobody@FreeBSD.org  Mon Nov  8 06:50:31 2010
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 6A3F8106566C
	for <freebsd-gnats-submit@FreeBSD.org>; Mon,  8 Nov 2010 06:50:31 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21])
	by mx1.freebsd.org (Postfix) with ESMTP id 587A28FC16
	for <freebsd-gnats-submit@FreeBSD.org>; Mon,  8 Nov 2010 06:50:31 +0000 (UTC)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.14.3/8.14.3) with ESMTP id oA86oVch089521
	for <freebsd-gnats-submit@FreeBSD.org>; Mon, 8 Nov 2010 06:50:31 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.14.3/8.14.3/Submit) id oA86oVQL089520;
	Mon, 8 Nov 2010 06:50:31 GMT
	(envelope-from nobody)
Message-Id: <201011080650.oA86oVQL089520@www.freebsd.org>
Date: Mon, 8 Nov 2010 06:50:31 GMT
From: Kelly Yancey <kbyanc@gmail.com>
To: freebsd-gnats-submit@FreeBSD.org
Subject: getifaddrs(3) returns truncated sockaddrs for netmasks
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         152036
>Category:       kern
>Synopsis:       [libc] getifaddrs(3) returns truncated sockaddrs for netmasks
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-net
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Nov 08 07:00:17 UTC 2010
>Closed-Date:    
>Last-Modified:  Tue Nov  6 12:30:00 UTC 2012
>Originator:     Kelly Yancey
>Release:        6.4, 8.1
>Organization:
>Environment:
FreeBSD gateway.posi.net 6.4-STABLE FreeBSD 6.4-STABLE #0: Thu Jan  7 13:48:25 JST 2010     root@gateway.posi.net:/usr/obj/usr/src/sys/GATEWAY  i386

-- AND --

FreeBSD gateway.posi.net 8.1-RELEASE FreeBSD 8.1-RELEASE #0: Mon Jul 19 02:55:53 UTC 2010     root@almeida.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC  i386
>Description:
The getifaddrs(3) function returns a pointer to a sockaddr for each of the interface's address, netmask, broadcast address, and destination address (for peer-to-peer links).  However, the sockaddr for IPv4 netmasks is frequently truncated to less than a full sockaddr_in.  In fact, it is typically truncated in the middle of the sin_addr field.

The sockaddr_in structures appear to be truncated to the minimum number of bytes necessary to hold the netmask.  For example, if the netmask was 255.255.254.0, then the sockaddr is truncated to just 7 bytes, with the sin_addr field consisting of just 3 bytes: 0xff, 0xff, 0xfe.

In other words, the sockaddr_in structure isn't just truncated for IPv4 netmasks, it is truncated in the middle of a primitive type (in this case, an uint32_t).

>How-To-Repeat:
Attached is a simple program that fetches and prints all of the interface addresses using the getifaddrs(3) API.  You will notice that the netmasks associated with the IPv4 addresses are all truncated to less than a full sockaddr_in.
>Fix:


Patch attached with submission follows:

/*
 *
 *
 */

#include <sys/types.h>
#include <sys/socket.h>

#include <net/if_dl.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <arpa/inet.h>

#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>

static void	 print_addr(const struct sockaddr *sa);

void
print_addr(const struct sockaddr *sa)
{
	char buffer[100];
	const struct sockaddr_in *sin;
	const struct sockaddr_in6 *sin6;
	const struct sockaddr_dl *sdl;
	int i;

	if (sa == NULL) {
		printf("NULL");
		return;
	}

	printf("(family: %d, len:%d", sa->sa_family, sa->sa_len);

#define	SIZECHECK(type) \
	if (sa->sa_len < sizeof(type)) { \
		printf(", TRUNCATED -- should be %zu bytes", sizeof(type)); \
		break; \
	}

	switch (sa->sa_family) {
	case AF_INET:
		SIZECHECK(struct sockaddr_in)
		sin = (const struct sockaddr_in *)sa;
		inet_ntop(AF_INET, &sin->sin_addr, buffer, sizeof(buffer));
		printf("addr:%s", buffer);
		break;
	case AF_INET6:
		SIZECHECK(struct sockaddr_in6)
		sin6 = (const struct sockaddr_in6 *)sa;
		inet_ntop(AF_INET6, &sin6->sin6_addr, buffer, sizeof(buffer));
		printf(", addr:%s", buffer);
		break;
	case AF_LINK:
		SIZECHECK(struct sockaddr_dl)
		sdl = (const struct sockaddr_dl *)sa;
		printf(", addr:%s", buffer);
		/*
		 * Could use link_ntoa() but its output format is a little
		 * unusual so print the address manually.
		 */ 
		for (i = 0; i < sdl->sdl_alen; i++) {
			if (i > 0)
				printf(":");
			printf("%02x", sdl->sdl_data[sdl->sdl_nlen + i]);
		}
		break;
	default:
		/* nothing */
		break;
	}

#undef SIZECHECK

	printf(")");
}

int
main(int ac __unused, char **av __unused)
{
	struct ifaddrs *addrlist, *addr;

	getifaddrs(&addrlist);

	for (addr = addrlist; addr != NULL; addr = addr->ifa_next) {
		printf("%s:\n", addr->ifa_name);
		printf("\tifa_addr = ");
		print_addr(addr->ifa_addr);
		printf("\n");

		printf("\tifa_netmask = ");
		print_addr(addr->ifa_netmask);
		printf("\n");

		printf("\tdstaddr = ");
		print_addr(addr->ifa_dstaddr);
		printf("\n\n");
	}

	freeifaddrs(addrlist);
	return 0;
}


>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->freebsd-net 
Responsible-Changed-By: linimon 
Responsible-Changed-When: Mon Jul 11 04:27:19 UTC 2011 
Responsible-Changed-Why:  
reclassify. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=152036 

From: Sergey Kandaurov <pluknet@gmail.com>
To: bug-followup@FreeBSD.org, kbyanc@gmail.com
Cc:  
Subject: Re: kern/152036: [libc] getifaddrs(3) returns truncated sockaddrs for netmasks
Date: Mon, 11 Jul 2011 17:59:47 +0400

 [Some thoughts and testing...]
 This is rather a kernel bug, i.e. this is not a getifaddrs() bug.
 This is confirmed by (undocumented) ioctl SIOCGIFNETMASK.
 I found that the bug is manifested for ip4, and not for lladdr, ipv6.

From: Kelly Yancey <kyancey@apple.com>
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/152036: [libc] getifaddrs(3) returns truncated sockaddrs for
 netmasks
Date: Tue, 12 Jul 2011 19:24:22 -0700

 Thanks, now lets just change the category to kern to reflect=85oh, wait.=

From: Nicholas Wilson <nicholas.wilson@realvnc.com>
To: bug-followup@FreeBSD.org, kbyanc@gmail.com
Cc:  
Subject: Re: kern/152036: [libc] getifaddrs(3) returns truncated sockaddrs
 for netmasks
Date: Tue, 06 Nov 2012 12:19:08 +0000

 Note that although this is a little surprising initially, it could well 
 be intentional. For comparison, SIOCGIFNETMASK has the same behaviour on 
 other platforms that have sa_len, including Darwin and AIX, so FreeBSD's 
 behaviour is in line with other implementations. Changing the behaviour 
 of the ioctl might break someone's code.
 
 Nicholas Wilson
>Unformatted:
