Friday, March 30, 2012

Validating link local ipv6 address

I have seen in many places using string comparison to validate link local ipv6 address. However I feel this approach is not ideal and may not fit in all use cases.

For ex in c++ you may write:

string s = "fe80::1234";
s.find("fe80::");

something of this sort. However what if IP address in capitals? The above code will fail.

Ok lets take string library approach

strncasecmp(addr, "fe80:",5) == 0;

This may also work fine. However I feel we can do these things better and right way using standard libraries provided by glibc.

If you need to check for string, use inet_pton() and IN6_IS_ADDR_LINKLOCAL() combination to achieve validation. If you have sockaddr_in6 handy, you only need to use IN6_IS_ADDR_LINKLOCAL(). So here is the program I wrote. I feel modularity is maintained in program to some extent. There are two APIs. One takes string as argument while the other takes sockaddr as argument. In second case, sockaddr in casted to sockaddr_in6 and then validated for link-local ipv6 address.

#include <stdio.h>
#include <netinet/in.h>

typedef _Bool BOOL;

#define B_TRUE  1
#define B_FALSE 0

BOOL is_link_local_ip (const struct sockaddr* sock);
BOOL is_link_local_ip_str (const char* address);

static inline BOOL __is_link_local (struct sockaddr_in6* sock)
{
    return (((IN6_IS_ADDR_LINKLOCAL(&sock->sin6_addr)) == 1)
                    ? B_TRUE : B_FALSE);
}

BOOL is_link_local_ip (const struct sockaddr* sock)
{
    if (sock)
        if (sock->sa_family == AF_INET6) {
            struct sockaddr_in6 *temp =
                    (struct sockaddr_in6*)(sock);
            return __is_link_local (temp);
        }
           

    return B_FALSE;
}

BOOL is_link_local_ip_str (const char *address)
{
    struct sockaddr_in6 __in6_addr;

    if (address)
        if (inet_pton(AF_INET6, address, &(__in6_addr.sin6_addr)))
            return __is_link_local (&__in6_addr);

    return B_FALSE;
}

int main ()
{
    const char* ip_addr = "FE80::224:2CFF:FEA1:8a1";

    if (is_link_local_ip_str(ip_addr))
        printf("Address is ipv6 link_local\n");
    else
        printf("Address is not ipv6 link local\n");
}


So here is the output: Address is ipv6 link_local

You can test program with different test vectors. Apart from link-local, there are lot such macros that come in handy. Please refer: http://uw714doc.sco.com/en/man/html.3N/inet.3N.html

As always leave comment if you have better approach