# HG changeset patch # User Sebastien Decugis # Date 1266305583 -32400 # Node ID 2b5027949f859fb4c1c720ae0741e92c9c320dd5 # Parent b9f48f2f2a226d7e747a14df3280aafa7ef11f92 Fix issue where the same address can be added several times in a list diff -r b9f48f2f2a22 -r 2b5027949f85 freeDiameter/endpoints.c --- a/freeDiameter/endpoints.c Tue Feb 16 15:29:55 2010 +0900 +++ b/freeDiameter/endpoints.c Tue Feb 16 16:33:03 2010 +0900 @@ -46,16 +46,18 @@ sSA4 *sin; sSA6 *sin6; } ptr; + in_port_t * port; int cmp = -1; TRACE_ENTRY("%p %p %u %x", list, sa, sl, flags); CHECK_PARAMS( list && sa && (sl <= sizeof(sSS)) ); + ptr.sa = sa; + /* Filter out a bunch of invalid addresses */ - if (! (flags & EP_ACCEPTALL)) { - ptr.sa = sa; - switch (sa->sa_family) { - case AF_INET: + switch (sa->sa_family) { + case AF_INET: + if (! (flags & EP_ACCEPTALL)) { if (IN_IS_ADDR_UNSPECIFIED(&ptr.sin->sin_addr) || IN_IS_ADDR_LOOPBACK(&ptr.sin->sin_addr) || IN_MULTICAST(ptr.sin->sin_addr.s_addr) @@ -63,32 +65,72 @@ || IN_BADCLASS(ptr.sin->sin_addr.s_addr) || (ptr.sin->sin_addr.s_addr == INADDR_BROADCAST)) return 0; - break; + } + port = &ptr.sin->sin_port; + break; - case AF_INET6: + case AF_INET6: + if (! (flags & EP_ACCEPTALL)) { if (IN6_IS_ADDR_UNSPECIFIED(&ptr.sin6->sin6_addr) || IN6_IS_ADDR_LOOPBACK(&ptr.sin6->sin6_addr) || IN6_IS_ADDR_MULTICAST(&ptr.sin6->sin6_addr) || IN6_IS_ADDR_LINKLOCAL(&ptr.sin6->sin6_addr) || IN6_IS_ADDR_SITELOCAL(&ptr.sin6->sin6_addr)) return 0; - break; + } + port = &ptr.sin6->sin6_port; + break; - default: - return 0; - } - } else { - /* remove it */ - flags &= ~EP_ACCEPTALL; + default: + return 0; } + + /* remove the ACCEPTALL flag */ + flags &= ~EP_ACCEPTALL; /* Search place in the list */ for (li = list->next; li != list; li = li->next) { ep = (struct fd_endpoint *)li; + in_port_t * ep_port; - cmp = memcmp(&ep->ss, sa, sl); - if (cmp >= 0) + /* First, compare the address family */ + if (ep->sa.sa_family < sa->sa_family) + continue; + if (ep->sa.sa_family > sa->sa_family) break; + + /* Then compare the address field */ + switch (sa->sa_family) { + case AF_INET: + cmp = memcmp(&ep->sin.sin_addr, &ptr.sin->sin_addr, sizeof(struct in_addr)); + ep_port = &ep->sin.sin_port; + break; + case AF_INET6: + cmp = memcmp(&ep->sin6.sin6_addr, &ptr.sin6->sin6_addr, sizeof(struct in6_addr)); + ep_port = &ep->sin6.sin6_port; + break; + default: + /* Filter this out */ + return 0; + } + if (cmp < 0) + continue; + if (cmp > 0) + break; + + /* Finally compare the port, only if not 0 */ + if (*port == 0) + break; + if (*ep_port == 0) { + /* save the port information in the list, and break */ + *ep_port = *port; + break; + } + if (*ep_port < *port) + continue; + if (*ep_port > *port) + cmp = 1; + break; } if (cmp) {