Index: sys/netinet/ip_output.c =================================================================== --- sys/netinet/ip_output.c +++ sys/netinet/ip_output.c @@ -108,7 +108,6 @@ ip_output_pfil(struct mbuf **mp, struct ifnet *ifp, struct inpcb *inp, struct sockaddr_in *dst, int *fibnum, int *error) { - struct m_tag *fwd_tag = NULL; struct mbuf *m; struct in_addr odst; struct ip *ip; @@ -182,13 +181,9 @@ return 1; /* Finished */ } /* Or forward to some other address? */ - if ((m->m_flags & M_IP_NEXTHOP) && - ((fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL)) { - bcopy((fwd_tag+1), dst, sizeof(struct sockaddr_in)); + if (IP_HAS_NEXTHOP(m) && !ip_get_fwdtag(m, dst, NULL)) { m->m_flags |= M_SKIP_FIREWALL; - m->m_flags &= ~M_IP_NEXTHOP; - m_tag_delete(m, fwd_tag); - + ip_flush_fwdtag(m); return -1; /* Reloop for CHANGE of dst */ } @@ -1415,3 +1410,79 @@ if_simloop(ifp, copym, AF_INET, 0); } } + +int +ip_set_fwdtag(struct mbuf *m, struct sockaddr_in *dst, u_short ifidx) +{ + struct sockaddr_in *sa; + struct m_tag *fwd_tag; + + (void)ifidx; /* XXX: store after dst, or make struct? */ + + fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); + if (fwd_tag != NULL) { + KASSERT(((struct sockaddr *)(fwd_tag+1))->sa_family == + AF_INET, ("%s: !AF_INET", __func__)); + + m_tag_unlink(m, fwd_tag); + } else { + fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD, sizeof(*dst), + M_NOWAIT); + if (fwd_tag == NULL) { + return 1; + } + } + + sa = (struct sockaddr_in *)(fwd_tag+1); + + bcopy(dst, sa, sizeof(*dst)); + m->m_flags |= M_IP_NEXTHOP; + + if (in_localip(sa->sin_addr)) + m->m_flags |= M_FASTFWD_OURS; + else + m->m_flags &= ~M_FASTFWD_OURS; + + m_tag_prepend(m, fwd_tag); + + return 0; +} + +int +ip_get_fwdtag(struct mbuf *m, struct sockaddr_in *dst, u_short *ifidx) +{ + struct m_tag *fwd_tag; + + fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); + if (fwd_tag == NULL) { + return 1; + } + + KASSERT(((struct sockaddr *)(fwd_tag+1))->sa_family == AF_INET, + ("%s: !AF_INET", __func__)); + + if (dst != NULL) { + bcopy((fwd_tag+1), dst, sizeof(*dst)); + } + + if (ifidx != NULL) { + /* XXX ifidx is not yet defined */ + } + + return 0; +} + +void +ip_flush_fwdtag(struct mbuf *m) +{ + struct m_tag *fwd_tag; + + fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); + if (fwd_tag != NULL) { + KASSERT(((struct sockaddr *)(fwd_tag+1))->sa_family == + AF_INET, ("%s: !AF_INET", __func__)); + + m->m_flags &= ~(M_IP_NEXTHOP | M_FASTFWD_OURS); + m_tag_delete(m, fwd_tag); + } +} Index: sys/netinet/ip_var.h =================================================================== --- sys/netinet/ip_var.h +++ sys/netinet/ip_var.h @@ -236,6 +236,11 @@ extern void (*ip_rsvp_force_done)(struct socket *); extern int (*rsvp_input_p)(struct mbuf **, int *, int); +#define IP_HAS_NEXTHOP(m) ((m)->m_flags & M_IP_NEXTHOP) +int ip_set_fwdtag(struct mbuf *, struct sockaddr_in *, u_short); +int ip_get_fwdtag(struct mbuf *, struct sockaddr_in *, u_short *); +void ip_flush_fwdtag(struct mbuf *); + VNET_DECLARE(struct pfil_head, inet_pfil_hook); /* packet filter hooks */ #define V_inet_pfil_hook VNET(inet_pfil_hook) Index: sys/netinet/tcp_input.c =================================================================== --- sys/netinet/tcp_input.c +++ sys/netinet/tcp_input.c @@ -605,6 +605,7 @@ int off0; int optlen = 0; #ifdef INET + struct sockaddr_in next_hop; int len; #endif int tlen = 0, off; @@ -615,8 +616,8 @@ uint8_t sig_checked = 0; #endif uint8_t iptos; - struct m_tag *fwd_tag = NULL; #ifdef INET6 + struct sockaddr_in6 next_hop6; struct ip6_hdr *ip6 = NULL; int isipv6; #else @@ -810,22 +811,6 @@ } else ti_locked = TI_UNLOCKED; - /* - * Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. - */ - if ( -#ifdef INET6 - (isipv6 && (m->m_flags & M_IP6_NEXTHOP)) -#ifdef INET - || (!isipv6 && (m->m_flags & M_IP_NEXTHOP)) -#endif -#endif -#if defined(INET) && !defined(INET6) - (m->m_flags & M_IP_NEXTHOP) -#endif - ) - fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); - findpcb: #ifdef INVARIANTS if (ti_locked == TI_RLOCKED) { @@ -835,10 +820,11 @@ } #endif #ifdef INET6 - if (isipv6 && fwd_tag != NULL) { - struct sockaddr_in6 *next_hop6; - - next_hop6 = (struct sockaddr_in6 *)(fwd_tag + 1); + /* + * Grab info from IP forward tag prepended to the chain. + */ + if (isipv6 && IP6_HAS_NEXTHOP(m) && + !ip6_get_fwdtag(m, &next_hop6, NULL)) { /* * Transparently forwarded. Pretend to be the destination. * Already got one like this? @@ -853,11 +839,13 @@ * any hardware-generated hash is ignored. */ inp = in6_pcblookup(&V_tcbinfo, &ip6->ip6_src, - th->th_sport, &next_hop6->sin6_addr, - next_hop6->sin6_port ? ntohs(next_hop6->sin6_port) : + th->th_sport, &next_hop6.sin6_addr, + next_hop6.sin6_port ? ntohs(next_hop6.sin6_port) : th->th_dport, INPLOOKUP_WILDCARD | INPLOOKUP_WLOCKPCB, m->m_pkthdr.rcvif); } + /* Remove the tag from the packet. We don't need it anymore. */ + ip6_flush_fwdtag(m); } else if (isipv6) { inp = in6_pcblookup_mbuf(&V_tcbinfo, &ip6->ip6_src, th->th_sport, &ip6->ip6_dst, th->th_dport, @@ -869,10 +857,10 @@ else #endif #ifdef INET - if (fwd_tag != NULL) { - struct sockaddr_in *next_hop; - - next_hop = (struct sockaddr_in *)(fwd_tag+1); + /* + * Grab info from IP forward tag prepended to the chain. + */ + if (IP_HAS_NEXTHOP(m) && !ip_get_fwdtag(m, &next_hop, NULL)) { /* * Transparently forwarded. Pretend to be the destination. * already got one like this? @@ -887,11 +875,13 @@ * any hardware-generated hash is ignored. */ inp = in_pcblookup(&V_tcbinfo, ip->ip_src, - th->th_sport, next_hop->sin_addr, - next_hop->sin_port ? ntohs(next_hop->sin_port) : + th->th_sport, next_hop.sin_addr, + next_hop.sin_port ? ntohs(next_hop.sin_port) : th->th_dport, INPLOOKUP_WILDCARD | INPLOOKUP_WLOCKPCB, m->m_pkthdr.rcvif); } + /* Remove the tag from the packet. We don't need it anymore. */ + ip_flush_fwdtag(m); } else inp = in_pcblookup_mbuf(&V_tcbinfo, ip->ip_src, th->th_sport, ip->ip_dst, th->th_dport, Index: sys/netinet/udp_usrreq.c =================================================================== --- sys/netinet/udp_usrreq.c +++ sys/netinet/udp_usrreq.c @@ -407,7 +407,7 @@ struct ip save_ip; struct sockaddr_in udp_in; struct mbuf *m; - struct m_tag *fwd_tag; + struct sockaddr_in next_hop; int cscov_partial, iphlen; m = *mp; @@ -647,14 +647,9 @@ */ /* - * Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. + * Grab info from IP forward tag prepended to the chain. */ - if ((m->m_flags & M_IP_NEXTHOP) && - (fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) { - struct sockaddr_in *next_hop; - - next_hop = (struct sockaddr_in *)(fwd_tag + 1); - + if (IP_HAS_NEXTHOP(m) && !ip_get_fwdtag(m, &next_hop, NULL)) { /* * Transparently forwarded. Pretend to be the destination. * Already got one like this? @@ -668,14 +663,13 @@ * any hardware-generated hash is ignored. */ inp = in_pcblookup(pcbinfo, ip->ip_src, - uh->uh_sport, next_hop->sin_addr, - next_hop->sin_port ? htons(next_hop->sin_port) : + uh->uh_sport, next_hop.sin_addr, + next_hop.sin_port ? htons(next_hop.sin_port) : uh->uh_dport, INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB, ifp); } /* Remove the tag from the packet. We don't need it anymore. */ - m_tag_delete(m, fwd_tag); - m->m_flags &= ~M_IP_NEXTHOP; + ip_flush_fwdtag(m); } else inp = in_pcblookup_mbuf(pcbinfo, ip->ip_src, uh->uh_sport, ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD | Index: sys/netinet6/ip6_output.c =================================================================== --- sys/netinet6/ip6_output.c +++ sys/netinet6/ip6_output.c @@ -322,8 +322,8 @@ int hdrsplit = 0; int sw_csum, tso; int needfiblookup; + int has_fwd_tag = 0; uint32_t fibnum; - struct m_tag *fwd_tag = NULL; uint32_t id; if (inp != NULL) { @@ -547,7 +547,7 @@ ro->ro_dst.sin6_family = AF_INET6; RT_VALIDATE((struct route *)ro, &inp->inp_rt_cookie, fibnum); } - if (ro->ro_rt && fwd_tag == NULL && (ro->ro_rt->rt_flags & RTF_UP) && + if (ro->ro_rt && has_fwd_tag && (ro->ro_rt->rt_flags & RTF_UP) && ro->ro_dst.sin6_family == AF_INET6 && IN6_ARE_ADDR_EQUAL(&ro->ro_dst.sin6_addr, &ip6->ip6_dst)) { rt = ro->ro_rt; @@ -556,7 +556,7 @@ if (ro->ro_lle) LLE_FREE(ro->ro_lle); /* zeros ro_lle */ ro->ro_lle = NULL; - if (fwd_tag == NULL) { + if (has_fwd_tag) { bzero(&dst_sa, sizeof(dst_sa)); dst_sa.sin6_family = AF_INET6; dst_sa.sin6_len = sizeof(dst_sa); @@ -860,13 +860,11 @@ goto done; } /* Or forward to some other address? */ - if ((m->m_flags & M_IP6_NEXTHOP) && - (fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) { + if (IP6_HAS_NEXTHOP(m) && !ip6_get_fwdtag(m, &dst_sa, NULL)) { dst = (struct sockaddr_in6 *)&ro->ro_dst; - bcopy((fwd_tag+1), &dst_sa, sizeof(struct sockaddr_in6)); m->m_flags |= M_SKIP_FIREWALL; - m->m_flags &= ~M_IP6_NEXTHOP; - m_tag_delete(m, fwd_tag); + ip6_flush_fwdtag(m); + has_fwd_tag = 1; goto again; } @@ -3096,3 +3094,90 @@ return len; #undef elen } + +int +ip6_set_fwdtag(struct mbuf *m, struct sockaddr_in6 *dst, u_short ifidx) +{ + struct sockaddr_in6 *sa6; + struct m_tag *fwd_tag; + + (void)ifidx; /* XXX: store after dst, or make struct? */ + + fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); + if (fwd_tag != NULL) { + KASSERT(((struct sockaddr *)(fwd_tag+1))->sa_family == + AF_INET6, ("%s: !AF_INET6", __func__)); + + m_tag_unlink(m, fwd_tag); + } else { + fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD, sizeof(*dst), + M_NOWAIT); + if (fwd_tag == NULL) { + return 1; + } + } + + sa6 = (struct sockaddr_in6 *)(fwd_tag+1); + + bcopy(dst, sa6, sizeof(*dst)); + + /* + * If nh6 address is link-local we should convert + * it to kernel internal form before doing any + * comparisons. + */ + if (sa6_embedscope(sa6, V_ip6_use_defzone) != 0) { + m_tag_free(fwd_tag); + return 1; + } + + if (in6_localip(&sa6->sin6_addr)) + m->m_flags |= M_FASTFWD_OURS; + else + m->m_flags &= ~M_FASTFWD_OURS; + + m->m_flags |= M_IP6_NEXTHOP; + + m_tag_prepend(m, fwd_tag); + + return 0; +} + +int +ip6_get_fwdtag(struct mbuf *m, struct sockaddr_in6 *dst, u_short *ifidx) +{ + struct m_tag *fwd_tag; + + fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); + if (fwd_tag == NULL) { + return 1; + } + + KASSERT(((struct sockaddr *)(fwd_tag+1))->sa_family == AF_INET6, + ("%s: !AF_INET6", __func__)); + + if (dst != NULL) { + bcopy((fwd_tag+1), dst, sizeof(*dst)); + } + + if (ifidx != NULL) { + /* XXX ifidx is not yet defined */ + } + + return 0; +} + +void +ip6_flush_fwdtag(struct mbuf *m) +{ + struct m_tag *fwd_tag; + + fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); + if (fwd_tag != NULL) { + KASSERT(((struct sockaddr *)(fwd_tag+1))->sa_family == + AF_INET6, ("%s: !AF_INET6", __func__)); + + m->m_flags &= ~(M_IP6_NEXTHOP | M_FASTFWD_OURS); + m_tag_delete(m, fwd_tag); + } +} Index: sys/netinet6/ip6_var.h =================================================================== --- sys/netinet6/ip6_var.h +++ sys/netinet6/ip6_var.h @@ -397,6 +397,11 @@ int ip6_fragment(struct ifnet *, struct mbuf *, int, u_char, int, uint32_t); +#define IP6_HAS_NEXTHOP(m) ((m)->m_flags & M_IP6_NEXTHOP) +int ip6_set_fwdtag(struct mbuf *, struct sockaddr_in6 *, u_short); +int ip6_get_fwdtag(struct mbuf *, struct sockaddr_in6 *, u_short *); +void ip6_flush_fwdtag(struct mbuf *); + int route6_input(struct mbuf **, int *, int); void frag6_init(void); Index: sys/netinet6/udp6_usrreq.c =================================================================== --- sys/netinet6/udp6_usrreq.c +++ sys/netinet6/udp6_usrreq.c @@ -204,7 +204,7 @@ int cscov_partial; int plen, ulen; struct sockaddr_in6 fromsa; - struct m_tag *fwd_tag; + struct sockaddr_in6 next_hop6; uint16_t uh_sum; uint8_t nxt; @@ -413,14 +413,9 @@ */ /* - * Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. + * Grab info from IP forward tag prepended to the chain. */ - if ((m->m_flags & M_IP6_NEXTHOP) && - (fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) { - struct sockaddr_in6 *next_hop6; - - next_hop6 = (struct sockaddr_in6 *)(fwd_tag + 1); - + if (IP6_HAS_NEXTHOP(m) && !ip6_get_fwdtag(m, &next_hop6, NULL)) { /* * Transparently forwarded. Pretend to be the destination. * Already got one like this? @@ -435,14 +430,13 @@ * any hardware-generated hash is ignored. */ inp = in6_pcblookup(pcbinfo, &ip6->ip6_src, - uh->uh_sport, &next_hop6->sin6_addr, - next_hop6->sin6_port ? htons(next_hop6->sin6_port) : + uh->uh_sport, &next_hop6.sin6_addr, + next_hop6.sin6_port ? htons(next_hop6.sin6_port) : uh->uh_dport, INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB, m->m_pkthdr.rcvif); } /* Remove the tag from the packet. We don't need it anymore. */ - m_tag_delete(m, fwd_tag); - m->m_flags &= ~M_IP6_NEXTHOP; + ip6_flush_fwdtag(m); } else inp = in6_pcblookup_mbuf(pcbinfo, &ip6->ip6_src, uh->uh_sport, &ip6->ip6_dst, uh->uh_dport, Index: sys/netpfil/ipfw/ip_fw_pfil.c =================================================================== --- sys/netpfil/ipfw/ip_fw_pfil.c +++ sys/netpfil/ipfw/ip_fw_pfil.c @@ -165,66 +165,25 @@ ret = EACCES; #else { - struct m_tag *fwd_tag; - size_t len; - KASSERT(args.next_hop == NULL || args.next_hop6 == NULL, ("%s: both next_hop=%p and next_hop6=%p not NULL", __func__, args.next_hop, args.next_hop6)); #ifdef INET6 - if (args.next_hop6 != NULL) - len = sizeof(struct sockaddr_in6); -#endif -#ifdef INET - if (args.next_hop != NULL) - len = sizeof(struct sockaddr_in); -#endif - - /* Incoming packets should not be tagged so we do not - * m_tag_find. Outgoing packets may be tagged, so we - * reuse the tag if present. - */ - fwd_tag = (dir == DIR_IN) ? NULL : - m_tag_find(*m0, PACKET_TAG_IPFORWARD, NULL); - if (fwd_tag != NULL) { - m_tag_unlink(*m0, fwd_tag); - } else { - fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD, len, - M_NOWAIT); - if (fwd_tag == NULL) { - ret = EACCES; - break; /* i.e. drop */ - } - } -#ifdef INET6 if (args.next_hop6 != NULL) { - struct sockaddr_in6 *sa6; - - sa6 = (struct sockaddr_in6 *)(fwd_tag + 1); - bcopy(args.next_hop6, sa6, len); - /* - * If nh6 address is link-local we should convert - * it to kernel internal form before doing any - * comparisons. - */ - if (sa6_embedscope(sa6, V_ip6_use_defzone) != 0) { + if (ip6_set_fwdtag(*m0, args.next_hop6, 0)) { ret = EACCES; break; } - if (in6_localip(&sa6->sin6_addr)) - (*m0)->m_flags |= M_FASTFWD_OURS; - (*m0)->m_flags |= M_IP6_NEXTHOP; } #endif #ifdef INET if (args.next_hop != NULL) { - bcopy(args.next_hop, (fwd_tag+1), len); - if (in_localip(args.next_hop->sin_addr)) - (*m0)->m_flags |= M_FASTFWD_OURS; - (*m0)->m_flags |= M_IP_NEXTHOP; + if (ip_set_fwdtag(*m0, args.next_hop, 0)) { + ret = EACCES; + break; + } } #endif - m_tag_prepend(*m0, fwd_tag); } #endif /* INET || INET6 */ break;