diff options
| author | George V. Neville-Neil <gnn@FreeBSD.org> | 2020-11-12 21:58:47 +0000 |
|---|---|---|
| committer | George V. Neville-Neil <gnn@FreeBSD.org> | 2020-11-12 21:58:47 +0000 |
| commit | 8ad114c082a159c0dde95aa35d2e3e108aa30a75 (patch) | |
| tree | b0a8c03ccb119a7ee684b5f01ffe4ad54992a1c6 /sys/netinet/ip_fastfwd.c | |
| parent | 9aa6d792b54934b896e3b4a1c21a2cfaa5f88e9d (diff) | |
Notes
Diffstat (limited to 'sys/netinet/ip_fastfwd.c')
| -rw-r--r-- | sys/netinet/ip_fastfwd.c | 58 |
1 files changed, 56 insertions, 2 deletions
diff --git a/sys/netinet/ip_fastfwd.c b/sys/netinet/ip_fastfwd.c index 10746a3e180f..aa5f6cf8e85d 100644 --- a/sys/netinet/ip_fastfwd.c +++ b/sys/netinet/ip_fastfwd.c @@ -111,6 +111,43 @@ __FBSDID("$FreeBSD$"); #include <machine/in_cksum.h> +#define V_ipsendredirects VNET(ipsendredirects) + +static struct mbuf * +ip_redir_alloc(struct mbuf *m, struct nhop_object *nh, + struct ip *ip, in_addr_t *addr) +{ + struct mbuf *mcopy = m_gethdr(M_NOWAIT, m->m_type); + if (mcopy != NULL && !m_dup_pkthdr(mcopy, m, M_NOWAIT)) { + /* + * It's probably ok if the pkthdr dup fails (because + * the deep copy of the tag chain failed), but for now + * be conservative and just discard the copy since + * code below may some day want the tags. + */ + m_free(mcopy); + return (NULL); + } + mcopy->m_len = min(ntohs(ip->ip_len), M_TRAILINGSPACE(mcopy)); + mcopy->m_pkthdr.len = mcopy->m_len; + m_copydata(m, 0, mcopy->m_len, mtod(mcopy, caddr_t)); + + if (nh != NULL && + ((nh->nh_flags & (NHF_REDIRECT|NHF_DEFAULT)) == 0)) { + struct in_ifaddr *nh_ia = (struct in_ifaddr *)(nh->nh_ifa); + u_long src = ntohl(ip->ip_src.s_addr); + + if (nh_ia != NULL && (src & nh_ia->ia_subnetmask) == nh_ia->ia_subnet) { + if (nh->nh_flags & NHF_GATEWAY) + *addr = nh->gw4_sa.sin_addr.s_addr; + else + *addr = ip->ip_dst.s_addr; + } + } + return (mcopy); +} + + static int ip_findroute(struct nhop_object **pnh, struct in_addr dest, struct mbuf *m) { @@ -156,13 +193,14 @@ ip_tryforward(struct mbuf *m) { struct ip *ip; struct mbuf *m0 = NULL; - struct nhop_object *nh; + struct nhop_object *nh = NULL; struct sockaddr_in dst; struct in_addr dest, odest, rtdest; uint16_t ip_len, ip_off; int error = 0; struct m_tag *fwd_tag = NULL; - + struct mbuf *mcopy = NULL; + struct in_addr redest; /* * Are we active and forwarding packets? */ @@ -387,6 +425,13 @@ passout: dst.sin_addr = dest; /* + * Handle redirect case. + */ + redest.s_addr = 0; + if (V_ipsendredirects && (nh->nh_ifp == m->m_pkthdr.rcvif)) + mcopy = ip_redir_alloc(m, nh, ip, &redest.s_addr); + + /* * Check if packet fits MTU or if hardware will fragment for us */ if (ip_len <= nh->nh_mtu) { @@ -455,7 +500,16 @@ passout: IPSTAT_INC(ips_forward); IPSTAT_INC(ips_fastforward); } + + /* Send required redirect */ + if (mcopy != NULL) { + icmp_error(mcopy, ICMP_REDIRECT, ICMP_REDIRECT_HOST, redest.s_addr, 0); + mcopy = NULL; /* Freed by caller */ + } + consumed: + if (mcopy != NULL) + m_freem(mcopy); return NULL; drop: if (m) |
