From 58230c23e2e4e1c694968f6a09d8cab46ecf9c7a Mon Sep 17 00:00:00 2001 From: Roy Marples Date: Wed, 9 Oct 2024 11:19:56 +0100 Subject: [PATCH] IPv6: Don't set IN6_IFF_TENTATIVE when the address exists We can only work it out when we know the address, not beforehand. --- src/ipv6.c | 91 ++++++++++++++++++++++++------------------------------ 1 file changed, 40 insertions(+), 51 deletions(-) diff --git a/src/ipv6.c b/src/ipv6.c index 7e2f0bb1..576c63d9 100644 --- a/src/ipv6.c +++ b/src/ipv6.c @@ -89,7 +89,6 @@ #ifdef IPV6_POLLADDRFLAG # warning kernel does not report IPv6 address flag changes -# warning polling tentative address flags periodically #endif /* Hackery at it's finest. */ @@ -661,8 +660,7 @@ ipv6_addaddr1(struct ipv6_addr *ia, const struct timespec *now) struct interface *ifp; uint32_t pltime, vltime; int loglevel; - struct ipv6_state *state; - struct ipv6_addr *ia2; + struct ipv6_addr *iaf; #ifdef __sun /* If we re-add then address on Solaris then the prefix @@ -678,8 +676,9 @@ ipv6_addaddr1(struct ipv6_addr *ia, const struct timespec *now) /* Remember the interface of the address. */ ifp = ia->iface; - if (!(ia->flags & IPV6_AF_DADCOMPLETED) && - ipv6_iffindaddr(ifp, &ia->addr, IN6_IFF_NOTUSEABLE)) + /* Find any existing address. */ + iaf = ipv6_iffindaddr(ifp, &ia->addr, 0); + if (iaf != NULL && !(iaf->addr_flags & IN6_IFF_NOTUSEABLE)) ia->flags |= IPV6_AF_DADCOMPLETED; /* Adjust plftime and vltime based on acquired time */ @@ -785,18 +784,15 @@ ipv6_addaddr1(struct ipv6_addr *ia, const struct timespec *now) /* Take a copy of the address and add it to our state if * it does not exist. * This is important if route overflow loses the message. */ - state = IPV6_STATE(ifp); - TAILQ_FOREACH(ia2, &state->addrs, next) { - if (IN6_ARE_ADDR_EQUAL(&ia2->addr, &ia->addr)) - break; - } - if (ia2 == NULL) { - if ((ia2 = malloc(sizeof(*ia2))) == NULL) { + if (iaf == NULL) { + struct ipv6_state *state = IPV6_STATE(ifp); + + if ((iaf = malloc(sizeof(*iaf))) == NULL) { logerr(__func__); return 0; /* Well, we did add the address */ } - memcpy(ia2, ia, sizeof(*ia2)); - TAILQ_INSERT_TAIL(&state->addrs, ia2, next); + memcpy(iaf, ia, sizeof(*iaf)); + TAILQ_INSERT_TAIL(&state->addrs, iaf, next); } return 0; @@ -1330,17 +1326,19 @@ ipv6_iffindaddr(struct interface *ifp, const struct in6_addr *addr, struct ipv6_addr *ap; state = IPV6_STATE(ifp); - if (state) { - TAILQ_FOREACH(ap, &state->addrs, next) { - if (addr == NULL) { - if (IN6_IS_ADDR_LINKLOCAL(&ap->addr) && - (!revflags || !(ap->addr_flags & revflags))) - return ap; - } else { - if (IN6_ARE_ADDR_EQUAL(&ap->addr, addr) && - (!revflags || !(ap->addr_flags & revflags))) - return ap; - } + if (state == NULL) + return NULL; + + TAILQ_FOREACH(ap, &state->addrs, next) { + if (addr == NULL) { + if (IN6_IS_ADDR_LINKLOCAL(&ap->addr) && + (!revflags || !(ap->addr_flags & revflags))) + return ap; + } else if (IN6_ARE_ADDR_EQUAL(&ap->addr, addr)) { + /* This is our address so we will return now */ + if (!revflags || !(ap->addr_flags & revflags)) + return ap; + return NULL; } } return NULL; @@ -1606,38 +1604,13 @@ ipv6_newaddr(struct interface *ifp, const struct in6_addr *addr, struct ipv6_addr *ia, *iaf; char buf[INET6_ADDRSTRLEN]; const char *cbp; - bool tempaddr; - int addr_flags; - -#ifdef IPV6_AF_TEMPORARY - tempaddr = flags & IPV6_AF_TEMPORARY; -#else - tempaddr = false; -#endif - - /* If adding a new DHCP / RA derived address, check current flags - * from an existing address. */ - if (tempaddr) - iaf = NULL; - else if (flags & IPV6_AF_AUTOCONF) - iaf = ipv6nd_iffindprefix(ifp, addr, prefix_len); - else - iaf = ipv6_iffindaddr(ifp, addr, 0); - if (iaf != NULL) { - addr_flags = iaf->addr_flags; - flags |= IPV6_AF_ADDED; - } else - addr_flags = IN6_IFF_TENTATIVE; ia = calloc(1, sizeof(*ia)); if (ia == NULL) goto err; ia->iface = ifp; - ia->addr_flags = addr_flags; ia->flags = IPV6_AF_NEW | flags; - if (!(ia->addr_flags & IN6_IFF_NOTUSEABLE)) - ia->flags |= IPV6_AF_DADCOMPLETED; ia->prefix_len = prefix_len; ia->dhcp6_fd = -1; @@ -1649,6 +1622,7 @@ ipv6_newaddr(struct interface *ifp, const struct in6_addr *addr, goto makepfx; else if (ia->flags & IPV6_AF_AUTOCONF) { ia->prefix = *addr; + iaf = ipv6nd_iffindprefix(ifp, addr, prefix_len); if (iaf != NULL) memcpy(&ia->addr, &iaf->addr, sizeof(ia->addr)); else { @@ -1666,7 +1640,7 @@ ipv6_newaddr(struct interface *ifp, const struct in6_addr *addr, cbp = inet_ntop(AF_INET6, &ia->addr, buf, sizeof(buf)); goto paddr; #else - return ia; + goto flags; #endif } else if (ia->flags & (IPV6_AF_REQUEST | IPV6_AF_PFXDELEGATION)) { ia->prefix = *addr; @@ -1686,6 +1660,21 @@ ipv6_newaddr(struct interface *ifp, const struct in6_addr *addr, goto err; snprintf(ia->saddr, sizeof(ia->saddr), "%s/%d", cbp, ia->prefix_len); +#ifndef __sun +flags: +#endif + /* If adding a new DHCP / RA derived address, check current flags + * from an existing address. */ + iaf = ipv6_iffindaddr(ifp, &ia->addr, 0); + if (iaf != NULL) { + ia->addr_flags = iaf->addr_flags; + ia->flags |= IPV6_AF_ADDED; + } else + ia->addr_flags |= IN6_IFF_TENTATIVE; + + if (!(ia->addr_flags & IN6_IFF_NOTUSEABLE)) + ia->flags |= IPV6_AF_DADCOMPLETED; + return ia; err: