Index: sys/netinet/icmp6.h =================================================================== --- sys/netinet/icmp6.h +++ sys/netinet/icmp6.h @@ -692,6 +692,8 @@ #define ICMPV6CTL_MAXID 26 #ifdef _KERNEL +#include + # ifdef __STDC__ struct nhop_object; struct rttimer; @@ -782,6 +784,9 @@ #define ICMP6_NODEINFO_NODEADDROK 0x2 #define ICMP6_NODEINFO_TMPADDROK 0x4 #define ICMP6_NODEINFO_GLOBALOK 0x8 + +SYSCTL_DECL(_net_inet6_icmp6); + #endif /* _KERNEL */ #endif /* not _NETINET_ICMP6_H_ */ Index: sys/netinet6/icmp6.c =================================================================== --- sys/netinet6/icmp6.c +++ sys/netinet6/icmp6.c @@ -129,6 +129,8 @@ VNET_DEFINE_STATIC(int, icmp6errpps_count) = 0; VNET_DEFINE_STATIC(struct timeval, icmp6errppslim_last); VNET_DECLARE(int, icmp6_nodeinfo); +VNET_DEFINE_STATIC(int, icmp6_rfi) = 0; +VNET_DEFINE_STATIC(char, reply_src6[IFNAMSIZ]); #define V_ripcbinfo VNET(ripcbinfo) #define V_ripcb VNET(ripcb) @@ -136,6 +138,8 @@ #define V_icmp6errpps_count VNET(icmp6errpps_count) #define V_icmp6errppslim_last VNET(icmp6errppslim_last) #define V_icmp6_nodeinfo VNET(icmp6_nodeinfo) +#define V_icmp6_rfi VNET(icmp6_rfi) +#define V_reply_src6 VNET(reply_src6) static void icmp6_errcount(int, int); static int icmp6_rip6_input(struct mbuf **, int); @@ -152,6 +156,14 @@ struct ifnet *, int); static int icmp6_notify_error(struct mbuf **, int, int, int); +SYSCTL_INT(_net_inet6_icmp6, OID_AUTO, reply_from_interface, CTLFLAG_VNET | CTLFLAG_RW, + &VNET_NAME(icmp6_rfi), 0, + "ICMP6 reply from incoming interface for non-local packets"); + +SYSCTL_STRING(_net_inet6_icmp6, OID_AUTO, reply_src, CTLFLAG_VNET | CTLFLAG_RW, + &VNET_NAME(reply_src6), IFNAMSIZ, + "ICMP6 reply source for non-local packets"); + /* * Kernel module interface for updating icmp6stat. The argument is an index * into icmp6stat treated as an array of u_quad_t. While this encodes the @@ -2125,25 +2137,46 @@ int error; struct in6_addr dst6; uint32_t scopeid; + struct ifnet *ifp; + struct ifaddr *ifa; /* * This case matches to multicasts, our anycast, or unicasts * that we do not own. Select a source address based on the * source address of the erroneous packet. */ - in6_splitscope(&ip6->ip6_src, &dst6, &scopeid); - error = in6_selectsrc_addr(M_GETFIB(m), &dst6, - scopeid, NULL, &src6, &hlim); + ifp = m->m_pkthdr.rcvif; + if (V_icmp6_rfi && ifp != NULL) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + ia = ifatoia6(ifa); + srcp = IA6_IN6(ia); + break; + } + } else if (V_reply_src6[0] != '\0' && (ifp = ifunit(V_reply_src6))) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + ia = ifatoia6(ifa); + srcp = IA6_IN6(ia); + break; + } + } else { + in6_splitscope(&ip6->ip6_src, &dst6, &scopeid); + error = in6_selectsrc_addr(M_GETFIB(m), &dst6, + scopeid, NULL, &src6, &hlim); - if (error) { - char ip6buf[INET6_ADDRSTRLEN]; - nd6log((LOG_DEBUG, - "icmp6_reflect: source can't be determined: " - "dst=%s, error=%d\n", - ip6_sprintf(ip6buf, &ip6->ip6_dst), error)); - goto bad; + if (error) { + char ip6buf[INET6_ADDRSTRLEN]; + nd6log((LOG_DEBUG, + "icmp6_reflect: source can't be determined: " + "dst=%s, error=%d\n", + ip6_sprintf(ip6buf, &ip6->ip6_dst), error)); + goto bad; + } + srcp = &src6; } - srcp = &src6; } /* * ip6_input() drops a packet if its src is multicast. Index: sys/netinet6/nd6_rtr.c =================================================================== --- sys/netinet6/nd6_rtr.c +++ sys/netinet6/nd6_rtr.c @@ -103,8 +103,6 @@ VNET_DEFINE(int, nd6_ignore_ipv6_only_ra) = 1; #endif -SYSCTL_DECL(_net_inet6_icmp6); - /* RTPREF_MEDIUM has to be 0! */ #define RTPREF_HIGH 1 #define RTPREF_MEDIUM 0