Add pack/unpack of IPv6 address in sync message in binary form similar to the ASCII :: A packed IPv6 address constists of - first byte high nibble first segment leng in bytes low nibble possition of last segment. then First segemnt i.e. left side of :: Last segment right side of :: Examle FC00::2 unpacked FC00 0000 0000 0000 0000 0000 0000 0002 packed 1F FC02 Example 2 2003::2:100 unpacked 2003 0000 0000 0000 0000 0000 0002 0100 packed 2D 20 03 02 01 00 Signed-off-by: Hans Schillstrom <hans.schillstrom@xxxxxxxxxxxx> --- net/netfilter/ipvs/ip_vs_sync.c | 128 +++++++++++++++++++++++++++++++++++--- 1 files changed, 117 insertions(+), 11 deletions(-) diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c index 00f0fd3..6b4976c 100644 --- a/net/netfilter/ipvs/ip_vs_sync.c +++ b/net/netfilter/ipvs/ip_vs_sync.c @@ -363,6 +363,65 @@ get_curr_sync_buff(unsigned long time) return sb; } +/* + * Try to pack an IPv6 address + * Note that buffer must be at least 17 bytes + * + * Packing adds a byte before packed address + * m.s.nibble first segment size in bytes + * l.s.nibble last segment start offset in bytes (size = 16 - lastSeg) + * + * Return packed size, 0=no reduction + * buffer contains first/lastSegemnt + (un)packed address + * + */ +static int ipv6addr_pack(struct in6_addr *in6, char *buffer) +{ + int i, pos=0, score=0; + int lmatch=0, firstSeg=0,lastSeg=0; + char *addr = in6->s6_addr; + char *buff = buffer; + + /* Check for more than 3 bytes of zeroes */ + for( i=0; i<16; i++) { + if ( *(addr++) ) { + score = 0; + continue; + } + if ( !score ) + pos = i; + score++; + if (score > lmatch) { + lmatch = score; + firstSeg = pos; /* Start of longest match */ + } + } + lastSeg = firstSeg + lmatch; + addr = in6->s6_addr; + /* Store length of first seg then size of last seg */ + *(buff++) = (firstSeg<<4 & 0xf0) | (lastSeg & 0xf); + memcpy(buff, addr, firstSeg); /* Copy first segment */ + buff += firstSeg; + memcpy(buff, addr+lastSeg, 16-lastSeg); + return 16 - lmatch; +} +/* + * unpack IPv6 address packed by above func. + */ +static int ipv6addr_unpack(char *buff, struct in6_addr *addr) +{ + int firstSeg, lastSeg; + + firstSeg = (*buff >> 4) & 0xf; + lastSeg = *(buff++) & 0xf; + addr->s6_addr32[0] = 0; + addr->s6_addr32[1] = 0; + addr->s6_addr32[2] = 0; + addr->s6_addr32[3] = 0; + memcpy(addr->s6_addr, buff, firstSeg); + memcpy(addr->s6_addr+lastSeg, buff+firstSeg, 16-lastSeg); + return 0; +} /* * Add an ip_vs_conn information into the current sync_buff. @@ -406,8 +465,8 @@ void ip_vs_sync_conn(struct ip_vs_conn *cp) len += pe_name_len + 2; len = (len+3) & 0xffc; /* Final 32 bit alignment */ - /* check if there is a space for this one */ - if (curr_sb && (curr_sb->head+len > curr_sb->end) ) { + /* check if there is a space for this one and offest for ipv6 pack*/ + if (curr_sb && (curr_sb->head+len+4 > curr_sb->end) ) { sb_queue_tail(curr_sb); curr_sb = NULL; } @@ -441,10 +500,26 @@ void ip_vs_sync_conn(struct ip_vs_conn *cp) #ifdef CONFIG_IP_VS_IPV6 if (cp->af == AF_INET6 ) { - p += sizeof(struct ip_vs_sync_v6); - ipv6_addr_copy(&s->v6.caddr, &cp->caddr.in6); - ipv6_addr_copy(&s->v6.vaddr, &cp->vaddr.in6); - ipv6_addr_copy(&s->v6.daddr, &cp->daddr.in6); + int psz; + p = (char *)&s->v6.caddr; + psz = ipv6addr_pack(&cp->caddr.in6, p); + psz += ipv6addr_pack(&cp->vaddr.in6, p+psz+1); + psz += ipv6addr_pack(&cp->vaddr.in6, p+psz+2); + if( psz >= 6 ) { + psz += 3; + p += psz; + s->v6.type |= STYPE_INET6_PACK; + len -= ((sizeof(struct in6_addr) * 3) - psz); + psz = sizeof(struct ip_vs_sync_v6) + - (sizeof(struct in6_addr) * 3) + psz; + s->v6.ver_size = htons(psz & SVER_MASK); + } + else { + p += sizeof(struct ip_vs_sync_v6); + ipv6_addr_copy(&s->v6.caddr, &cp->caddr.in6); + ipv6_addr_copy(&s->v6.vaddr, &cp->vaddr.in6); + ipv6_addr_copy(&s->v6.daddr, &cp->daddr.in6); + } } else #endif { @@ -508,13 +583,14 @@ ip_vs_conn_fill_param_sync(int af, union ip_vs_sync_conn *sc, int pe_data_len, char *pe_name, int pe_name_len ) { #ifdef CONFIG_IP_VS_IPV6 - if ( af == AF_INET6 ) - ip_vs_conn_fill_param(af, sc->v6.protocol, + if ( af == AF_INET6 ) { + if (!(sc->v6.type & STYPE_INET6_PACK)) + ip_vs_conn_fill_param(af, sc->v6.protocol, (const union nf_inet_addr *)&sc->v6.caddr, sc->v6.cport, (const union nf_inet_addr *)&sc->v6.vaddr, sc->v6.vport, p); - else + } else #endif ip_vs_conn_fill_param(af, sc->v4.protocol, (const union nf_inet_addr *)&sc->v4.caddr, @@ -780,7 +856,16 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen) if (s->v6.type & STYPE_INET6 ) { #ifdef CONFIG_IP_VS_IPV6 af = AF_INET6; - p += sizeof(struct ip_vs_sync_v6); + if (s->v6.type & STYPE_INET6_PACK ) { + p = (char*) &s->v6.caddr; + p += 1 + ((*p >> 4) & 0xf) /* len + First seg */ + + (16 - (*p & 0xf )); /* + Last seg */ + p += 1 + ((*p >> 4) & 0xf) /* len + First seg */ + + (16 - (*p & 0xf )); /* + Last seg */ + p += 1 + ((*p >> 4) & 0xf) /* len + First seg */ + + (16 - (*p & 0xf )); /* + Last seg */ + } else + p += sizeof(struct ip_vs_sync_v6); #else IP_VS_DBG(2,"IPv6 sync message received, and IPVS is not compiled for IPv6\n"); p = (char *)s + size; @@ -891,7 +976,27 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen) ? &opt : NULL), pp); #ifdef CONFIG_IP_VS_IPV6 - else + else { + /* Check if packed IPv6 */ + if (s->v6.type & STYPE_INET6_PACK ) { + union nf_inet_addr vaddr, daddr, caddr; + int ret; + p = (char*) &s->v6.caddr; + ret = ipv6addr_unpack(p, &caddr.in6); + p += 1 + ((*p >> 4) & 0xf) + (16 - (*p & 0xf )); + ret |= ipv6addr_unpack(p, &vaddr.in6); + p += 1 + ((*p >> 4) & 0xf) + (16 - (*p & 0xf )); + ret |= ipv6addr_unpack(p, &daddr.in6); + if (ret) { + IP_VS_ERR_RL("Invalid packed IPv6 add in sync msg\n"); + return; + } + ip_vs_conn_fill_param(af, s->v6.protocol, + &caddr, s->v6.cport, + &vaddr, s->v6.vport, + ¶m); + + } ip_vs_proc_conn(¶m, flags, state, s->v6.protocol, af, (union nf_inet_addr *)&s->v6.daddr, @@ -900,6 +1005,7 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen) (opt_flags & IPVS_OPT_F_SEQ_DATA ? &opt : NULL), pp); + } #endif p = (char *)s + size; } /* End of for(...) */ -- 1.7.0.1 -- To unsubscribe from this list: send the line "unsubscribe lvs-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html