On Wed, Jun 01, 2016 at 03:47:45PM +0200, Mike Belopuhov wrote:
> On 1 June 2016 at 13:33, Patrick Wildt <patr...@blueri.se> wrote:
> > Hi,
> >
> > The IPv6 address assignment was basically copied from the IPv4
> > code.  Instead of working on the last 32-bits, it actually worked
> > on the fourth byte.  Thus it modified the network bits instead of
> > the host bits.
> >
> > This diff fixes the code so that we can have at least a 32-bit
> > address pool space by using the current IPv4 code.  In the future
> > it might be nice to be able to leverage all host bits.
> >
> > Is there a saner way to access the last 32-bits of an IPv6 address?
> > Another possibility would be
> >
> >     *((uint32_t *)&in6->sin6_addr.s6_addr[12]) = ...;
> >
> > but I'm not sure that's any better.
> >
> 
> The best way to do it is via memcpy.  Save htonl(host) in a uint32_t
> on the stack and memcpy it into the (char *)&...s6_addr[12].
> 
> I think __u6_addr.__u6_addr32 is an implementation detail.
> 
> > Patrick
> >
> 

Ok, how is this?

diff --git sbin/iked/ikev2.c sbin/iked/ikev2.c
index d4c4290..60a1850 100644
--- sbin/iked/ikev2.c
+++ sbin/iked/ikev2.c
@@ -5044,7 +5044,7 @@ ikev2_cp_setaddr(struct iked *env, struct iked_sa *sa, 
sa_family_t family)
        struct sockaddr_in6     *in6 = NULL, *cfg6 = NULL;
        struct iked_sa           key;
        struct iked_addr         addr;
-       uint32_t                 mask, host, lower, upper, start;
+       uint32_t                 mask, host, lower, upper, start, nhost;
        size_t                   i;
 
        switch (family) {
@@ -5092,15 +5092,13 @@ ikev2_cp_setaddr(struct iked *env, struct iked_sa *sa, 
sa_family_t family)
                return (-1);
        }
 
-       /* truncate prefixlen in the v6 case */
-       mask = prefixlen2mask(ikecfg->cfg.address.addr_mask);
-
        switch (addr.addr_af) {
        case AF_INET:
                cfg4 = (struct sockaddr_in *)&ikecfg->cfg.address.addr;
                in4 = (struct sockaddr_in *)&addr.addr;
                in4->sin_family = AF_INET;
                in4->sin_len = sizeof(*in4);
+               mask = prefixlen2mask(ikecfg->cfg.address.addr_mask);
                lower = ntohl(cfg4->sin_addr.s_addr & ~mask);
                key.sa_addrpool = &addr;
                break;
@@ -5109,7 +5107,12 @@ ikev2_cp_setaddr(struct iked *env, struct iked_sa *sa, 
sa_family_t family)
                in6 = (struct sockaddr_in6 *)&addr.addr;
                in6->sin6_family = AF_INET6;
                in6->sin6_len = sizeof(*in6);
-               lower = cfg6->sin6_addr.s6_addr[3];
+               /* truncate prefixlen to get a 32-bit space */
+               mask = (ikecfg->cfg.address.addr_mask >= 96)
+                   ? prefixlen2mask(ikecfg->cfg.address.addr_mask - 96)
+                   : prefixlen2mask(0);
+               memcpy(&lower, &cfg6->sin6_addr.s6_addr[12], sizeof(uint32_t));
+               lower = ntohl(lower & ~mask);
                key.sa_addrpool6 = &addr;
                break;
        default:
@@ -5133,7 +5136,9 @@ ikev2_cp_setaddr(struct iked *env, struct iked_sa *sa, 
sa_family_t family)
                        break;
                case AF_INET6:
                        memcpy(in6, cfg6, sizeof(*in6));
-                       in6->sin6_addr.s6_addr[3] = htonl(host);
+                       nhost = htonl(host);
+                       memcpy(&in6->sin6_addr.s6_addr[12], &nhost,
+                           sizeof(uint32_t));
                        break;
                }
                if ((addr.addr_af == AF_INET &&

Reply via email to