Properly initialize zone index. And use in_conninfo from PCB to be able disambiguate a possibly ambiguous address. --- sys/netinet/tcp_input.c (svn+ssh://svn.freebsd.org/base/head) (revision 261548) +++ sys/netinet/tcp_input.c (working copy) @@ -98,6 +98,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -232,8 +233,9 @@ static void tcp_newreno_partial_ack(struct tcpcb static void inline tcp_fields_to_host(struct tcphdr *); #ifdef TCP_SIGNATURE static void inline tcp_fields_to_net(struct tcphdr *); -static int inline tcp_signature_verify_input(struct mbuf *, int, int, - int, struct tcpopt *, struct tcphdr *, u_int); +static int inline tcp_signature_verify_input(struct mbuf *, + struct in_conninfo *, int, int, + struct tcpopt *, struct tcphdr *, u_int); #endif static void inline cc_ack_received(struct tcpcb *tp, struct tcphdr *th, uint16_t type); @@ -477,13 +479,13 @@ tcp_fields_to_net(struct tcphdr *th) } static inline int -tcp_signature_verify_input(struct mbuf *m, int off0, int tlen, int optlen, - struct tcpopt *to, struct tcphdr *th, u_int tcpbflag) +tcp_signature_verify_input(struct mbuf *m, struct in_conninfo *inc, int tlen, + int optlen, struct tcpopt *to, struct tcphdr *th, u_int tcpbflag) { int ret; tcp_fields_to_net(th); - ret = tcp_signature_verify(m, off0, tlen, optlen, to, th, tcpbflag); + ret = tcp_signature_verify(m, inc, tlen, optlen, to, th, tcpbflag); tcp_fields_to_host(th); return (ret); } @@ -532,6 +534,7 @@ tcp6_input(struct mbuf **mp, int *offp, int proto) { struct mbuf *m = *mp; struct in6_ifaddr *ia6; + struct ip6_hdr *ip6; IP6_EXTHDR_CHECK(m, *offp, sizeof(struct tcphdr), IPPROTO_DONE); @@ -539,12 +542,12 @@ tcp6_input(struct mbuf **mp, int *offp, int proto) * draft-itojun-ipv6-tcp-to-anycast * better place to put this in? */ - ia6 = ip6_getdstifaddr(m); + ip6 = mtod(m, struct ip6_hdr *); + ia6 = in6ifa_ifwithaddr(&ip6->ip6_dst, + in6_getscopezone(m->m_pkthdr.rcvif, + in6_addrscope(&ip6->ip6_dst))); if (ia6 && (ia6->ia6_flags & IN6_IFF_ANYCAST)) { - struct ip6_hdr *ip6; - ifa_free(&ia6->ia_ifa); - ip6 = mtod(m, struct ip6_hdr *); icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR, (caddr_t)&ip6->ip6_dst - (caddr_t)ip6); return IPPROTO_DONE; @@ -1063,6 +1066,11 @@ relocked: inc.inc_flags |= INC_ISIPV6; inc.inc6_faddr = ip6->ip6_src; inc.inc6_laddr = ip6->ip6_dst; + if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src) || + IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst)) + inc.inc6_zoneid = in6_getscopezone( + m->m_pkthdr.rcvif, + IPV6_ADDR_SCOPE_LINKLOCAL); } else #endif { @@ -1138,7 +1146,8 @@ relocked: if (sig_checked == 0) { tcp_dooptions(&to, optp, optlen, (thflags & TH_SYN) ? TO_SYN : 0); - if (!tcp_signature_verify_input(m, off0, tlen, + if (!tcp_signature_verify_input(m, + &tp->t_inpcb->inp_inc, tlen, optlen, &to, th, tp->t_flags)) { /* @@ -1266,7 +1275,9 @@ relocked: if (isipv6 && !V_ip6_use_deprecated) { struct in6_ifaddr *ia6; - ia6 = ip6_getdstifaddr(m); + ia6 = in6ifa_ifwithaddr(&ip6->ip6_dst, + in6_getscopezone(m->m_pkthdr.rcvif, + in6_addrscope(&ip6->ip6_dst))); if (ia6 != NULL && (ia6->ia6_flags & IN6_IFF_DEPRECATED)) { ifa_free(&ia6->ia_ifa); @@ -1378,8 +1389,8 @@ relocked: if (sig_checked == 0) { tcp_dooptions(&to, optp, optlen, (thflags & TH_SYN) ? TO_SYN : 0); - if (!tcp_signature_verify_input(m, off0, tlen, optlen, &to, - th, tp->t_flags)) { + if (!tcp_signature_verify_input(m, &tp->t_inpcb->inp_inc, + tlen, optlen, &to, th, tp->t_flags)) { /* * In SYN_SENT state if it receives an RST, it is