Quantcast

getifaddrs() and IPv6 link-local addresses

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

getifaddrs() and IPv6 link-local addresses

Simon Perreault-2
Hi,

Is it normal that getifaddrs() leaks the kernel's scope ID
representation of IPv6 link-local addresses?

In other words, is every user of getifaddrs() expected to fill the
sin6_scope_id member from the 3rd byte of the address, and then clear
that byte?

Looking at ifconfig.c, it's full of calls to this function:

> void
> in6_fillscopeid(struct sockaddr_in6 *sin6)
> {
> #ifdef __KAME__
>         if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
>                 sin6->sin6_scope_id =
>                         ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
>                 sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
>         }
> #endif /* __KAME__ */
> }

Shouldn't this be done once in getifaddrs() itself instead of replicated
everywhere it's used?

Simon

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: getifaddrs() and IPv6 link-local addresses

Todd T. Fries-2
Penned by Simon Perreault on 20120830 13:47.22, we have:
| Hi,
|
| Is it normal that getifaddrs() leaks the kernel's scope ID
| representation of IPv6 link-local addresses?
|
| In other words, is every user of getifaddrs() expected to fill the
| sin6_scope_id member from the 3rd byte of the address, and then
| clear that byte?
|
| Looking at ifconfig.c, it's full of calls to this function:
|
| >void
| >in6_fillscopeid(struct sockaddr_in6 *sin6)
| >{
| >#ifdef __KAME__
| >        if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
| >                sin6->sin6_scope_id =
| >                        ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
| >                sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
| >        }
| >#endif /* __KAME__ */
| >}
|
| Shouldn't this be done once in getifaddrs() itself instead of
| replicated everywhere it's used?
|
| Simon

I'm sure people will correct me if I am misremembering but .. to the best of
my understanding...

It would be ideal for the kernel to use the sin6_scope_id when communicating with
userland everywhere, and never should the userland have to do the horrendous
hacks required to clear this from the s6_addr[2] and s6_addr[3] fields.

No one has taken this on, and so this desire for cleaning the ugly mess KAME left
us has been left undone.

Thanks,
--
Todd Fries .. [hidden email]

 _____________________________________________
|                                             \  1.636.410.0632 (voice)
| Free Daemon Consulting, LLC                 \  1.405.227.9094 (voice)
| http://FreeDaemonConsulting.com             \  1.866.792.3418 (FAX)
| 2525 NW Expy #525, Oklahoma City, OK 73112  \  sip:[hidden email]
| "..in support of free software solutions."  \  sip:[hidden email]
 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
                                                 
              37E7 D3EB 74D0 8D66 A68D  B866 0326 204E 3F42 004A
                        http://todd.fries.net/pgp.txt

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: getifaddrs() and IPv6 link-local addresses

Tomek Mrugalski
On 30.08.2012 20:50, Todd T. Fries wrote:

> Penned by Simon Perreault on 20120830 13:47.22, we have:
> | Hi,
> |
> | Is it normal that getifaddrs() leaks the kernel's scope ID
> | representation of IPv6 link-local addresses?
> |
> | In other words, is every user of getifaddrs() expected to fill the
> | sin6_scope_id member from the 3rd byte of the address, and then
> | clear that byte?
> |
> | Looking at ifconfig.c, it's full of calls to this function:
> |
> | >void
> | >in6_fillscopeid(struct sockaddr_in6 *sin6)
> | >{
> | >#ifdef __KAME__
> | >        if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
> | >                sin6->sin6_scope_id =
> | >                        ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
> | >                sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
> | >        }
> | >#endif /* __KAME__ */
> | >}
> |
> | Shouldn't this be done once in getifaddrs() itself instead of
> | replicated everywhere it's used?
> |
> | Simon
>
> I'm sure people will correct me if I am misremembering but .. to the best of
> my understanding...
>
> It would be ideal for the kernel to use the sin6_scope_id when communicating with
> userland everywhere, and never should the userland have to do the horrendous
> hacks required to clear this from the s6_addr[2] and s6_addr[3] fields.
As a person who never touched kernel space in OpenBSD, I fully agree.

> No one has taken this on, and so this desire for cleaning the ugly mess KAME left
> us has been left undone.
Hi,

Leaking scope ID to userspace is only one part of the story. The other
direction seems to be broken as well. My link-local address is
fe80::a:b:c:d and the iterface index is 2. I was able to bind a udp
socket to fe80:2::a:b:c:d address, transmit *and* receive data. (the
data received sent to fe80::a:b:c:d, yet I was able to receive it). Call
to bind() should fail in the first place.

If you are interested in the reproduction code, you may want to use
latest dibbler git repo (see http://klub.com.pl/dhcpv6/ for details).
The code for socket operations is in Port-bsd/lowlevel-bsd.c. It is
shared between all BSDs and Mac OS.

If you decide that for some reason you do not want to fix this, it
should be at least documented somewhere. A simple sentence in getifaddrs
man page would be helpful. Obviously, fixing the code is more preferable.

Cheers,
Tomek

p.s.
What's the recommended API a userland application (dhcpv6 client) should
use for adding/updating lifetimes/removing IPv6 addresses on an
interface? How about the same for configuring prefixes?

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: getifaddrs() and IPv6 link-local addresses

Simon Perreault-2
Le 2012-08-31 03:34, Tomek Mrugalski a écrit :
> If you decide that for some reason you do not want to fix this,

I think it's pretty clear that something has to be fixed.

I'm wondering why FreeBSD doesn't have the same issues. Looking at the
code I can't figure it out.

> What's the recommended API a userland application (dhcpv6 client) should
> use for adding/updating lifetimes/removing IPv6 addresses on an
> interface?

It's all ioctls.

add: SIOCAIFADDR_IN6
remove: SIOCDIFADDR_IN6
update lifetime: SIOCSIFALIFETIME_IN6

Check out ifconfig.c for examples.
http://www.openbsd.org/cgi-bin/cvsweb/src/sbin/ifconfig/ifconfig.c

> How about the same for configuring prefixes?

Not sure what you mean. The SIOCAIFADDR_IN6 ioctl takes a struct
in6_aliasreq argument, which has a prefix mask member.

Simon

Loading...