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>