Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 27 Jun 2011 12:21:11 +0000 (UTC)
From:      Gleb Smirnoff <glebius@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r223593 - in head/sys: modules/ipdivert netinet netinet/ipfw
Message-ID:  <201106271221.p5RCLBm2097410@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: glebius
Date: Mon Jun 27 12:21:11 2011
New Revision: 223593
URL: http://svn.freebsd.org/changeset/base/223593

Log:
  Add possibility to pass IPv6 packets to a divert(4) socket.
  
  Submitted by:	sem

Modified:
  head/sys/modules/ipdivert/Makefile
  head/sys/netinet/ip_divert.c
  head/sys/netinet/ipfw/ip_fw_pfil.c

Modified: head/sys/modules/ipdivert/Makefile
==============================================================================
--- head/sys/modules/ipdivert/Makefile	Mon Jun 27 11:49:58 2011	(r223592)
+++ head/sys/modules/ipdivert/Makefile	Mon Jun 27 12:21:11 2011	(r223593)
@@ -3,6 +3,11 @@
 .PATH: ${.CURDIR}/../../netinet
 
 KMOD=   ipdivert
-SRCS=   ip_divert.c
+SRCS=   ip_divert.c opt_inet6.h
+
+.if !defined(KERNBUILDDIR)
+opt_inet6.h:
+	echo "#define INET6 1" > ${.TARGET}
+.endif
 
 .include <bsd.kmod.mk>

Modified: head/sys/netinet/ip_divert.c
==============================================================================
--- head/sys/netinet/ip_divert.c	Mon Jun 27 11:49:58 2011	(r223592)
+++ head/sys/netinet/ip_divert.c	Mon Jun 27 12:21:11 2011	(r223593)
@@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$");
 #error "IPDIVERT requires INET."
 #endif
 #endif
+#include "opt_inet6.h"
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -62,6 +63,10 @@ __FBSDID("$FreeBSD$");
 #include <netinet/in_var.h>
 #include <netinet/ip.h>
 #include <netinet/ip_var.h>
+#ifdef INET6
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+#endif
 #ifdef SCTP
 #include <netinet/sctp_crc32.h>
 #endif
@@ -312,10 +317,10 @@ static int
 div_output(struct socket *so, struct mbuf *m, struct sockaddr_in *sin,
     struct mbuf *control)
 {
+	struct ip *const ip = mtod(m, struct ip *);
 	struct m_tag *mtag;
 	struct ipfw_rule_ref *dt;
 	int error = 0;
-	struct mbuf *options;
 
 	/*
 	 * An mbuf may hasn't come from userland, but we pretend
@@ -367,71 +372,103 @@ div_output(struct socket *so, struct mbu
 
 	/* Reinject packet into the system as incoming or outgoing */
 	if (!sin || sin->sin_addr.s_addr == 0) {
-		struct ip *const ip = mtod(m, struct ip *);
+		struct mbuf *options = NULL;
 		struct inpcb *inp;
 
 		dt->info |= IPFW_IS_DIVERT | IPFW_INFO_OUT;
 		inp = sotoinpcb(so);
 		INP_RLOCK(inp);
-		/*
-		 * Don't allow both user specified and setsockopt options,
-		 * and don't allow packet length sizes that will crash
-		 */
-		if (((ip->ip_hl != (sizeof (*ip) >> 2)) && inp->inp_options) ||
-		     ((u_short)ntohs(ip->ip_len) > m->m_pkthdr.len)) {
-			error = EINVAL;
-			INP_RUNLOCK(inp);
-			m_freem(m);
-		} else {
+		switch (ip->ip_v) {
+		case IPVERSION:
+			/*
+			 * Don't allow both user specified and setsockopt
+			 * options, and don't allow packet length sizes that
+			 * will crash.
+			 */
+			if ((((ip->ip_hl << 2) != sizeof(struct ip)) &&
+			    inp->inp_options != NULL) ||
+			    ((u_short)ntohs(ip->ip_len) > m->m_pkthdr.len)) {
+				error = EINVAL;
+				INP_RUNLOCK(inp);
+				goto cantsend;
+			}
+
 			/* Convert fields to host order for ip_output() */
 			ip->ip_len = ntohs(ip->ip_len);
 			ip->ip_off = ntohs(ip->ip_off);
+			break;
+#ifdef INET6
+		case IPV6_VERSION >> 4:
+		    {
+			struct ip6_hdr *const ip6 = mtod(m, struct ip6_hdr *);
+
+			/* Don't allow packet length sizes that will crash */
+			if (((u_short)ntohs(ip6->ip6_plen) > m->m_pkthdr.len)) {
+				error = EINVAL;
+				INP_RUNLOCK(inp);
+				goto cantsend;
+			}
 
-			/* Send packet to output processing */
-			KMOD_IPSTAT_INC(ips_rawout);		/* XXX */
+			ip6->ip6_plen = ntohs(ip6->ip6_plen);
+		    }
+#endif
+		default:
+			error = EINVAL;
+			INP_RUNLOCK(inp);
+			goto cantsend;
+		}
+
+		/* Send packet to output processing */
+		KMOD_IPSTAT_INC(ips_rawout);		/* XXX */
 
 #ifdef MAC
-			mac_inpcb_create_mbuf(inp, m);
+		mac_inpcb_create_mbuf(inp, m);
 #endif
-			/*
-			 * Get ready to inject the packet into ip_output().
-			 * Just in case socket options were specified on the
-			 * divert socket, we duplicate them.  This is done
-			 * to avoid having to hold the PCB locks over the call
-			 * to ip_output(), as doing this results in a number of
-			 * lock ordering complexities.
-			 *
-			 * Note that we set the multicast options argument for
-			 * ip_output() to NULL since it should be invariant that
-			 * they are not present.
-			 */
-			KASSERT(inp->inp_moptions == NULL,
-			    ("multicast options set on a divert socket"));
-			options = NULL;
-			/*
-			 * XXXCSJP: It is unclear to me whether or not it makes
-			 * sense for divert sockets to have options.  However,
-			 * for now we will duplicate them with the INP locks
-			 * held so we can use them in ip_output() without
-			 * requring a reference to the pcb.
-			 */
-			if (inp->inp_options != NULL) {
-				options = m_dup(inp->inp_options, M_DONTWAIT);
-				if (options == NULL)
-					error = ENOBUFS;
-			}
-			INP_RUNLOCK(inp);
-			if (error == ENOBUFS) {
-				m_freem(m);
-				return (error);
+		/*
+		 * Get ready to inject the packet into ip_output().
+		 * Just in case socket options were specified on the
+		 * divert socket, we duplicate them.  This is done
+		 * to avoid having to hold the PCB locks over the call
+		 * to ip_output(), as doing this results in a number of
+		 * lock ordering complexities.
+		 *
+		 * Note that we set the multicast options argument for
+		 * ip_output() to NULL since it should be invariant that
+		 * they are not present.
+		 */
+		KASSERT(inp->inp_moptions == NULL,
+		    ("multicast options set on a divert socket"));
+		/*
+		 * XXXCSJP: It is unclear to me whether or not it makes
+		 * sense for divert sockets to have options.  However,
+		 * for now we will duplicate them with the INP locks
+		 * held so we can use them in ip_output() without
+		 * requring a reference to the pcb.
+		 */
+		if (inp->inp_options != NULL) {
+			options = m_dup(inp->inp_options, M_NOWAIT);
+			if (options == NULL) {
+				INP_RUNLOCK(inp);
+				error = ENOBUFS;
+				goto cantsend;
 			}
+		}
+		INP_RUNLOCK(inp);
+
+		switch (ip->ip_v) {
+		case IPVERSION:
 			error = ip_output(m, options, NULL,
-			    ((so->so_options & SO_DONTROUTE) ?
-			    IP_ROUTETOIF : 0) | IP_ALLOWBROADCAST |
-			    IP_RAWOUTPUT, NULL, NULL);
-			if (options != NULL)
-				m_freem(options);
+			    ((so->so_options & SO_DONTROUTE) ? IP_ROUTETOIF : 0)
+			    | IP_ALLOWBROADCAST | IP_RAWOUTPUT, NULL, NULL);
+			break;
+#ifdef INET6
+		case IPV6_VERSION >> 4:
+			error = ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
+			break;
+#endif
 		}
+		if (options != NULL)
+			m_freem(options);
 	} else {
 		dt->info |= IPFW_IS_DIVERT | IPFW_INFO_IN;
 		if (m->m_pkthdr.rcvif == NULL) {
@@ -456,14 +493,26 @@ div_output(struct socket *so, struct mbu
 		mac_socket_create_mbuf(so, m);
 #endif
 		/* Send packet to input processing via netisr */
-		netisr_queue_src(NETISR_IP, (uintptr_t)so, m);
+		switch (ip->ip_v) {
+		case IPVERSION:
+			netisr_queue_src(NETISR_IP, (uintptr_t)so, m);
+			break;
+#ifdef INET6
+		case IPV6_VERSION >> 4:
+			netisr_queue_src(NETISR_IPV6, (uintptr_t)so, m);
+			break;
+#endif
+		default:
+			error = EINVAL;
+			goto cantsend;
+		}
 	}
 
-	return error;
+	return (error);
 
 cantsend:
 	m_freem(m);
-	return error;
+	return (error);
 }
 
 static int

Modified: head/sys/netinet/ipfw/ip_fw_pfil.c
==============================================================================
--- head/sys/netinet/ipfw/ip_fw_pfil.c	Mon Jun 27 11:49:58 2011	(r223592)
+++ head/sys/netinet/ipfw/ip_fw_pfil.c	Mon Jun 27 12:21:11 2011	(r223593)
@@ -58,6 +58,10 @@ __FBSDID("$FreeBSD$");
 #include <netinet/ip.h>
 #include <netinet/ip_var.h>
 #include <netinet/ip_fw.h>
+#ifdef INET6
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+#endif
 #include <netinet/ipfw/ip_fw_private.h>
 #include <netgraph/ng_ipfw.h>
 
@@ -265,7 +269,7 @@ ipfw_divert(struct mbuf **m0, int incomi
 	 * If not tee, consume packet and send it to divert socket.
 	 */
 	struct mbuf *clone;
-	struct ip *ip;
+	struct ip *ip = mtod(*m0, struct ip *);
 	struct m_tag *tag;
 
 	/* Cloning needed for tee? */
@@ -289,8 +293,9 @@ ipfw_divert(struct mbuf **m0, int incomi
 	 * Note that we now have the 'reass' ipfw option so if we care
 	 * we can do it before a 'tee'.
 	 */
-	ip = mtod(clone, struct ip *);
-	if (!tee && ntohs(ip->ip_off) & (IP_MF | IP_OFFMASK)) {
+	if (!tee) switch (ip->ip_v) {
+	case IPVERSION:
+	    if (ntohs(ip->ip_off) & (IP_MF | IP_OFFMASK)) {
 		int hlen;
 		struct mbuf *reass;
 
@@ -312,7 +317,26 @@ ipfw_divert(struct mbuf **m0, int incomi
 		else
 			ip->ip_sum = in_cksum(reass, hlen);
 		clone = reass;
+	    }
+	    break;
+#ifdef INET6
+	case IPV6_VERSION >> 4:
+	    {
+	    struct ip6_hdr *const ip6 = mtod(clone, struct ip6_hdr *);
+
+		if (ip6->ip6_nxt == IPPROTO_FRAGMENT) {
+			int nxt, off;
+
+			off = sizeof(struct ip6_hdr);
+			nxt = frag6_input(&clone, &off, 0);
+			if (nxt == IPPROTO_DONE)
+				return (0);
+		}
+		break;
+	    }
+#endif
 	}
+
 	/* attach a tag to the packet with the reinject info */
 	tag = m_tag_alloc(MTAG_IPFW_RULE, 0,
 		    sizeof(struct ipfw_rule_ref), M_NOWAIT);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201106271221.p5RCLBm2097410>