Hi Willy,

> static inline void inet_set_tos(int fd, sa_family_t family, int tos)
> {
>     if (family != AF_INET && family != AF_INET6)
>         return;
> #if defined(IP_TOS)
>     if (setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) == 0)
>         return;
> #endif
> #if defined(IPV6_TCLASS)
>     if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos) == 0)
>         return;
> #endif
> }

Since setsockopt always returns 0, the function will return too early to
set IPV6_TCLASS.

However we can - as per RFC2553 section 3.7 - use the libc macro
IN6_IS_ADDR_V4MAPPED(), to test whether the IPv6 address is actually
a V4-mapped-in-V6 adress (so we set IP_TOS) or a proper IPv6 address (so
we set IPV6_TCLASS).

Instead of the sa_family_t I'm passing the whole sockaddr_storage struct
to the function, so I can access the actual IPv6 address. Let me know if
there are any implications of doing so:

static inline void inet_set_tos(int fd, struct sockaddr_storage from, int tos)
{
#ifdef IP_TOS
    if (from.ss_family == AF_INET)
        setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
#endif
#ifdef IPV6_TCLASS
    if (from.ss_family != AF_INET6)
        return;
    if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&from)->sin6_addr))
        setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
    else
        setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos));
#endif
}


Thats means we make a single (the correct one) syscall only, and all 3
scenarios (native IPv4, native IPv6 and v4-in-v6-mapped) are covered.

To maintain compatibility we put everything v6 related in #ifdef's of
IPV6_TCLASS.

In case the libc doesn't have that macro, but defines other IPv6 related
things like IPV6_TCLASS, we add a compatibility define in compat.h:

#if defined(IPV6_TCLASS) && !defined(IN6_IS_ADDR_V4MAPPED)
#define IN6_IS_ADDR_V4MAPPED(a) \
((((const uint32_t *) (a))[0] == 0) \
&& (((const uint32_t *) (a))[1] == 0) \
&& (((const uint32_t *) (a))[2] == htonl (0xffff)))
#endif



> We could emit a warning if IPV6_TCLASS is not defined when the set-tos
> is used, but quite frankly, it could upset users who are only using IPV4.

I agree, I didn't think of that. The user may not be able to change the
underlying kernel/libc and a warning can be annoying. Also this is only
interesting for one situation: when IPv6 is used, but IPV6_TCLASS is not
defined, and that particular case will probably never happen in real life.


Let me know if you are ok with the approach above.



Best regards,

Lukas                                     

Reply via email to