aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/netinet/ip_fastfwd.c58
-rw-r--r--sys/netinet/ip_input.c9
-rw-r--r--sys/netinet/ip_var.h2
3 files changed, 64 insertions, 5 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)
diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c
index bbc81977ccef..7d6c4a378b4d 100644
--- a/sys/netinet/ip_input.c
+++ b/sys/netinet/ip_input.c
@@ -111,8 +111,11 @@ SYSCTL_INT(_net_inet_ip, IPCTL_FORWARDING, forwarding, CTLFLAG_VNET | CTLFLAG_RW
&VNET_NAME(ipforwarding), 0,
"Enable IP forwarding between interfaces");
-VNET_DEFINE_STATIC(int, ipsendredirects) = 1; /* XXX */
-#define V_ipsendredirects VNET(ipsendredirects)
+/*
+ * Respond with an ICMP host redirect when we forward a packet out of
+ * the same interface on which it was received. See RFC 792.
+ */
+VNET_DEFINE(int, ipsendredirects) = 1;
SYSCTL_INT(_net_inet_ip, IPCTL_SENDREDIRECTS, redirect, CTLFLAG_VNET | CTLFLAG_RW,
&VNET_NAME(ipsendredirects), 0,
"Enable sending IP redirects");
@@ -571,7 +574,7 @@ tooshort:
* case skip another inbound firewall processing and update
* ip pointer.
*/
- if (V_ipforwarding != 0 && V_ipsendredirects == 0
+ if (V_ipforwarding != 0
#if defined(IPSEC) || defined(IPSEC_SUPPORT)
&& (!IPSEC_ENABLED(ipv4) ||
IPSEC_CAPS(ipv4, m, IPSEC_CAP_OPERABLE) == 0)
diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h
index b6693eb58200..77b6ee88507a 100644
--- a/sys/netinet/ip_var.h
+++ b/sys/netinet/ip_var.h
@@ -182,6 +182,7 @@ struct inpcbinfo;
VNET_DECLARE(int, ip_defttl); /* default IP ttl */
VNET_DECLARE(int, ipforwarding); /* ip forwarding */
+VNET_DECLARE(int, ipsendredirects);
#ifdef IPSTEALTH
VNET_DECLARE(int, ipstealth); /* stealth forwarding */
#endif
@@ -197,6 +198,7 @@ extern struct pr_usrreqs rip_usrreqs;
#define V_ip_id VNET(ip_id)
#define V_ip_defttl VNET(ip_defttl)
#define V_ipforwarding VNET(ipforwarding)
+#define V_ipsendredirects VNET(ipsendredirects)
#ifdef IPSTEALTH
#define V_ipstealth VNET(ipstealth)
#endif