Add IPv6 "scope" for link-local addresses.
authorAlan T. DeKok <aland@freeradius.org>
Sat, 6 Mar 2010 13:26:27 +0000 (14:26 +0100)
committerAlan T. DeKok <aland@freeradius.org>
Sat, 6 Mar 2010 20:05:15 +0000 (21:05 +0100)
Added to fr_ipaddr_t.
fr_ipaddr_cmp(), fr_sockaddr2ipaddr(), fr_ipaddr2sockaddr().

Also made ip_hton() call fr_sockaddr2ipaddr() to prevent code duplication.

src/include/libradius.h
src/lib/misc.c

index 71e8604..b21593e 100644 (file)
@@ -198,6 +198,7 @@ typedef struct fr_ipaddr_t {
                struct in_addr  ip4addr;
                struct in6_addr ip6addr; /* maybe defined in missing.h */
        } ipaddr;
+       uint32_t        scope;  /* for IPv6 */
 } fr_ipaddr_t;
 
 /*
index 544ef82..6963505 100644 (file)
@@ -405,14 +405,14 @@ const char *inet_ntop(int af, const void *src, char *dst, size_t cnt)
  */
 int ip_hton(const char *src, int af, fr_ipaddr_t *dst)
 {
-       int error;
+       int rcode;
        struct addrinfo hints, *ai = NULL, *res = NULL;
 
        memset(&hints, 0, sizeof(hints));
        hints.ai_family = af;
 
-       if ((error = getaddrinfo(src, NULL, &hints, &res)) != 0) {
-               fr_strerror_printf("ip_hton: %s", gai_strerror(error));
+       if ((rcode = getaddrinfo(src, NULL, &hints, &res)) != 0) {
+               fr_strerror_printf("ip_hton: %s", gai_strerror(rcode));
                return -1;
        }
 
@@ -427,32 +427,11 @@ int ip_hton(const char *src, int af, fr_ipaddr_t *dst)
                return -1;
        }
 
-       switch (ai->ai_family) {
-       case AF_INET :
-               dst->af = AF_INET;
-               memcpy(&dst->ipaddr,
-                      &((struct sockaddr_in*)ai->ai_addr)->sin_addr,
-                      sizeof(struct in_addr));
-               break;
-
-#ifdef HAVE_STRUCT_SOCKADDR_IN6
-       case AF_INET6 :
-               dst->af = AF_INET6;
-               memcpy(&dst->ipaddr,
-                      &((struct sockaddr_in6*)ai->ai_addr)->sin6_addr,
-                      sizeof(struct in6_addr));
-               break;
-#endif
-
-               /* Flow should never reach here */
-       case AF_UNSPEC :
-       default :
-               fr_strerror_printf("ip_hton found unusable information for host %.100s", src);
-               freeaddrinfo(ai);
-               return -1;
-       }
-
+       rcode = fr_sockaddr2ipaddr((struct sockaddr_storage *)ai->ai_addr,
+                                  ai->ai_addrlen, dst, NULL);
        freeaddrinfo(ai);
+       if (!rcode) return -1;
+
        return 0;
 }
 
@@ -573,6 +552,9 @@ int fr_ipaddr_cmp(const fr_ipaddr_t *a, const fr_ipaddr_t *b)
 
 #ifdef HAVE_STRUCT_SOCKADDR_IN6
        case AF_INET6:
+               if (a->scope < b->scope) return -1;
+               if (a->scope > b->scope) return +1;
+
                return memcmp(&a->ipaddr.ip6addr,
                              &b->ipaddr.ip6addr,
                              sizeof(a->ipaddr.ip6addr));
@@ -611,6 +593,7 @@ int fr_ipaddr2sockaddr(const fr_ipaddr_t *ipaddr, int port,
                s6.sin6_family = AF_INET6;
                s6.sin6_addr = ipaddr->ipaddr.ip6addr;
                s6.sin6_port = htons(port);
+               s6.sin6_scope_id = ipaddr->scope;
                memset(sa, 0, sizeof(*sa));
                memcpy(sa, &s6, sizeof(s6));
 #endif
@@ -623,15 +606,15 @@ int fr_ipaddr2sockaddr(const fr_ipaddr_t *ipaddr, int port,
 
 
 int fr_sockaddr2ipaddr(const struct sockaddr_storage *sa, socklen_t salen,
-                      fr_ipaddr_t *ipaddr, int * port)
+                      fr_ipaddr_t *ipaddr, int *port)
 {
-       /*
-        *      FIXME: Check salen against sizeof socket structures.
-        */
-       salen = salen;          /* -Wunused */
-
        if (sa->ss_family == AF_INET) {
                struct sockaddr_in      s4;
+
+               if (salen < sizeof(s4)) {
+                       fr_strerror_printf("IPv4 address is too small");
+                       return 0;
+               }
                
                memcpy(&s4, sa, sizeof(s4));
                ipaddr->af = AF_INET;
@@ -642,13 +625,21 @@ int fr_sockaddr2ipaddr(const struct sockaddr_storage *sa, socklen_t salen,
        } else if (sa->ss_family == AF_INET6) {
                struct sockaddr_in6     s6;
                
+               if (salen < sizeof(s6)) {
+                       fr_strerror_printf("IPv6 address is too small");
+                       return 0;
+               }
+               
                memcpy(&s6, sa, sizeof(s6));
                ipaddr->af = AF_INET6;
                ipaddr->ipaddr.ip6addr = s6.sin6_addr;
                if (port) *port = ntohs(s6.sin6_port);
+               ipaddr->scope = s6.sin6_scope_id;
 #endif
 
        } else {
+               fr_strerror_printf("Unsupported address famility %d",
+                                  sa->ss_family);
                return 0;
        }