Index: sys/net/route/route_helpers.c =================================================================== --- sys/net/route/route_helpers.c +++ sys/net/route/route_helpers.c @@ -60,6 +60,7 @@ #endif #ifdef INET6 #include +#include #endif #include @@ -85,6 +86,91 @@ RIB_RLOCK(rnh); rnh->rnh_walktree(&rnh->head, (walktree_f_t *)wa_f, arg); RIB_RUNLOCK(rnh); +} + +static int +contigmask(const uint8_t *p, int len) +{ + int i, n; + + for (i = 0; i < len ; i++) + if ( (p[i/8] & (1 << (7 - (i%8)))) == 0) /* first bit unset */ + break; + for (n= i + 1; n < len; n++) + if ( (p[n/8] & (1 << (7 - (n % 8)))) != 0) + return (-1); /* mask not contiguous */ + return (i); +} + +/* + * Exports address from @rt into @dst and fills @plen with prefix length. + * Assumes @dst has enough buffer to store sockaddr of the relevant address + * family from @rt. + * @dst is filled in with IPv6 addresses in normal (deembedded form). + * + * Returns 0 on success. + */ +int +rt_export_prefix(const struct rtentry *rt, struct sockaddr *dst, int *plen) +{ +#ifdef INET + struct sockaddr_in *dst4; +#endif +#ifdef INET6 + struct sockaddr_in6 *dst6; +#endif + const struct sockaddr *sa; + + sa = rt_key_const(rt); + + switch (sa->sa_family) { +#ifdef INET + case AF_INET: + /* Construct clean copy of dst */ + dst4 = (struct sockaddr_in *)dst; + bzero(dst4, sizeof(struct sockaddr_in)); + dst4->sin_family = AF_INET; + dst4->sin_len = sizeof(struct sockaddr_in); + dst4->sin_addr = ((const struct sockaddr_in *)sa)->sin_addr; + /* Calculate netmask */ + sa = rt_mask_const(rt); + if (sa != NULL) { + const struct in_addr *mask4; + mask4 = &((const struct sockaddr_in *)sa)->sin_addr; + *plen = contigmask((const uint8_t *)mask4, 32); + } else + *plen = 32; + break; +#endif +#ifdef INET6 + case AF_INET6: + /* Construct clean copy of dst */ + dst6 = (struct sockaddr_in6 *)dst; + bzero(dst6, sizeof(struct sockaddr_in6)); + dst6->sin6_family = AF_INET6; + dst6->sin6_len = sizeof(struct sockaddr_in6); + dst6->sin6_addr = ((const struct sockaddr_in6 *)sa)->sin6_addr; + /* Deembed scopeid */ + struct in6_addr *addr6 = &dst6->sin6_addr; + if (IN6_IS_SCOPE_LINKLOCAL(addr6)) { + dst6->sin6_scope_id = htonl(ntohs(in6_getscope(addr6))); + in6_set_unicast_scopeid(addr6, 0); + } + /* Calculate netmask */ + sa = rt_mask_const(rt); + if (sa != NULL) { + const struct in6_addr *mask6; + mask6 = &((const struct sockaddr_in6 *)sa)->sin6_addr; + *plen = contigmask((const uint8_t *)mask6, 128); + } else + *plen = 128; + break; +#endif + default: + return (EAFNOSUPPORT); + } + + return (0); } /* Index: sys/net/route/route_var.h =================================================================== --- sys/net/route/route_var.h +++ sys/net/route/route_var.h @@ -110,6 +110,8 @@ struct radix_node *rt_mpath_unlink(struct rib_head *rnh, struct rt_addrinfo *info, struct rtentry *rto, int *perror); #endif +int rt_export_prefix(const struct rtentry *rt, struct sockaddr *dst, int *plen); + int add_route(struct rib_head *rnh, struct rt_addrinfo *info, struct rtentry **ret_nrt); int del_route(struct rib_head *rnh, struct rt_addrinfo *info, Index: sys/netpfil/ipfw/ip_fw_table_algo.c =================================================================== --- sys/netpfil/ipfw/ip_fw_table_algo.c +++ sys/netpfil/ipfw/ip_fw_table_algo.c @@ -58,6 +58,7 @@ #include /* struct ipfw_rule_ref */ #include #include +#include #include #include @@ -3798,7 +3799,7 @@ static int ta_dump_kfib_tentry(void *ta_state, struct table_info *ti, void *e, ipfw_obj_tentry *tent); static int ta_dump_kfib_tentry_int(struct sockaddr *paddr, - struct sockaddr *pmask, ipfw_obj_tentry *tent); + int plen, ipfw_obj_tentry *tent); static int ta_find_kfib_tentry(void *ta_state, struct table_info *ti, ipfw_obj_tentry *tent); static void ta_foreach_kfib(void *ta_state, struct table_info *ti, @@ -3918,10 +3919,10 @@ tinfo->flags = IPFW_TATFLAGS_AFDATA; tinfo->taclass4 = IPFW_TACLASS_RADIX; tinfo->count4 = 0; - tinfo->itemsize4 = sizeof(struct rtentry); + tinfo->itemsize4 = 0; /* unused */ tinfo->taclass6 = IPFW_TACLASS_RADIX; tinfo->count6 = 0; - tinfo->itemsize6 = sizeof(struct rtentry); + tinfo->itemsize6 = 0; /* unused */ } static int @@ -3943,39 +3944,36 @@ ta_dump_kfib_tentry(void *ta_state, struct table_info *ti, void *e, ipfw_obj_tentry *tent) { - struct rtentry *rte; + struct sockaddr_in6 dst; + int plen; - rte = (struct rtentry *)e; + bzero(&dst, sizeof(dst)); - return ta_dump_kfib_tentry_int(rt_key(rte), rt_mask(rte), tent); + rt_export_prefix((struct rtentry *)e, (struct sockaddr *)&dst, &plen); + /* Embed scope for IPv6 link-local addresses */ + struct in6_addr *addr6 = &dst.sin6_addr; + if (dst.sin6_family == AF_INET6 && IN6_IS_SCOPE_LINKLOCAL(addr6)) + in6_set_unicast_scopeid(addr6, ntohl(dst.sin6_scope_id)); + + return (ta_dump_kfib_tentry_int((struct sockaddr *)&dst, plen, tent)); } static int -ta_dump_kfib_tentry_int(struct sockaddr *paddr, struct sockaddr *pmask, - ipfw_obj_tentry *tent) +ta_dump_kfib_tentry_int(struct sockaddr *paddr, int plen, ipfw_obj_tentry *tent) { #ifdef INET - struct sockaddr_in *addr, *mask; + struct sockaddr_in *addr; #endif #ifdef INET6 - struct sockaddr_in6 *addr6, *mask6; + struct sockaddr_in6 *addr6; #endif - int len; - len = 0; - /* Guess IPv4/IPv6 radix by sockaddr family */ #ifdef INET if (paddr->sa_family == AF_INET) { addr = (struct sockaddr_in *)paddr; - mask = (struct sockaddr_in *)pmask; tent->k.addr.s_addr = addr->sin_addr.s_addr; - len = 32; - if (mask != NULL) - len = contigmask((uint8_t *)&mask->sin_addr, 32); - if (len == -1) - len = 0; - tent->masklen = len; + tent->masklen = plen; tent->subtype = AF_INET; tent->v.kidx = 0; /* Do we need to put GW here? */ } @@ -3983,15 +3981,9 @@ #ifdef INET6 if (paddr->sa_family == AF_INET6) { addr6 = (struct sockaddr_in6 *)paddr; - mask6 = (struct sockaddr_in6 *)pmask; memcpy(&tent->k.addr6, &addr6->sin6_addr, sizeof(struct in6_addr)); - len = 128; - if (mask6 != NULL) - len = contigmask((uint8_t *)&mask6->sin6_addr, 128); - if (len == -1) - len = 0; - tent->masklen = len; + tent->masklen = plen; tent->subtype = AF_INET6; tent->v.kidx = 0; } @@ -4007,6 +3999,7 @@ struct rt_addrinfo info; struct sockaddr_in6 key6, dst6, mask6; struct sockaddr *dst, *key, *mask; + int plen; /* Prepare sockaddr for prefix/mask and info */ bzero(&dst6, sizeof(dst6)); @@ -4038,7 +4031,23 @@ if ((info.rti_addrs & RTA_NETMASK) == 0) mask = NULL; - ta_dump_kfib_tentry_int(dst, mask, tent); + if (tent->subtype == AF_INET) { + if (mask != NULL) { + struct in_addr *addr4; + addr4 = &((struct sockaddr_in *)mask)->sin_addr; + plen = contigmask((uint8_t *)addr4, 32); + } else + plen = 32; + } else { + if (mask != NULL) { + struct in6_addr *addr6; + addr6 = &((struct sockaddr_in6 *)mask)->sin6_addr; + plen = contigmask((uint8_t *)addr6, 128); + } else + plen = 128; + } + + ta_dump_kfib_tentry_int(dst, plen, tent); return (0); }