Does PPTP over IPv6 exists?

Alexander Motin mav at alkar.net
Sat Oct 7 10:12:02 PDT 2006


Hi.

Last week I have made many changes in mpd4 CVS to enable IPv6 support. 
As result, IPV6CP and IPv6 console is now supported, TCP and UDP link 
types perfectly work over IPv6.

But when I have touched PPTP, I have found two problems:
1. There seems like no special support for inet6/raw/gre in kernel, so 
at the beginning, when GRE packets pass through ipfw, ipfw can't 
recognize header 47(GRE), and then, if using sysctl I allow them to 
pass, ng_pptpgre is getting them without IP header.
2. There is no support for IPv6 in ng_pptpgre, so it tries to cut 
unexisting IPv4 header from packet.

I have not found in Internet any documents about specific suport of PPTP 
over IPv6, but I also have not found that it must not work. And I have a 
stupid question: "Should PPTP at all work over IPv6?".

Does anybody know something about PPTP and IPv6? What side is right: it 
should work, but nobody try to do it yet, or it should work in different 
way, or it should not work at all?

When I have tried to fix ng_pptpgre with patch in attachment and allowed 
ipfw to pass unknown packets, mpd4 was able to successfully make PPTP 
connection over IPv6 and transmit both IPv4 and IPv6 packets. So, it 
should do it or not?

-- 
Alexander Motin
-------------- next part --------------
--- ng_pptpgre.c.orig	Tue Sep 20 16:40:55 2005
+++ ng_pptpgre.c	Sat Oct  7 18:53:04 2006
@@ -67,6 +67,7 @@
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
+#include <netinet/ip6.h>
 
 #include <netgraph/ng_message.h>
 #include <netgraph/netgraph.h>
@@ -588,6 +589,7 @@
 	int iphlen, grelen, extralen;
 	const struct greheader *gre;
 	const struct ip *ip;
+	const u_int8_t *ipv;
 	int error = 0;
 	struct mbuf *m;
 
@@ -598,40 +600,89 @@
 	priv->stats.recvPackets++;
 	priv->stats.recvOctets += m->m_pkthdr.len;
 
+	/* Get the first byte to identify protocol */
 	/* Sanity check packet length */
-	if (m->m_pkthdr.len < sizeof(*ip) + sizeof(*gre)) {
+	if (m->m_pkthdr.len < 1) {
 		priv->stats.recvRunts++;
 		ERROUT(EINVAL);
 	}
 
-	/* Safely pull up the complete IP+GRE headers */
-	if (m->m_len < sizeof(*ip) + sizeof(*gre)
-	    && (m = m_pullup(m, sizeof(*ip) + sizeof(*gre))) == NULL) {
+	/* Safely pull up the first byte of headers */
+	if (m->m_len < 1
+	    && (m = m_pullup(m, 1)) == NULL) {
 		priv->stats.memoryFailures++;
 		ERROUT(ENOBUFS);
 	}
-	ip = mtod(m, const struct ip *);
-	iphlen = ip->ip_hl << 2;
-	if (m->m_len < iphlen + sizeof(*gre)) {
-		if ((m = m_pullup(m, iphlen + sizeof(*gre))) == NULL) {
+	ipv = mtod(m, const u_int8_t *);
+	
+	if ((((*ipv)&IPV6_VERSION_MASK)==0x40) && (((*ipv)&(~IPV6_VERSION_MASK))>=5)) { 
+	    /* There is IPv4 header, remove it */
+
+		/* Sanity check packet length */
+		if (m->m_pkthdr.len < sizeof(*ip) + sizeof(*gre)) {
+			priv->stats.recvRunts++;
+			ERROUT(EINVAL);
+		}
+
+		/* Safely pull up the complete IP+GRE headers */
+		if (m->m_len < sizeof(*ip) + sizeof(*gre)
+		    && (m = m_pullup(m, sizeof(*ip) + sizeof(*gre))) == NULL) {
 			priv->stats.memoryFailures++;
 			ERROUT(ENOBUFS);
 		}
 		ip = mtod(m, const struct ip *);
-	}
-	gre = (const struct greheader *)((const u_char *)ip + iphlen);
-	grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck);
-	if (m->m_pkthdr.len < iphlen + grelen) {
-		priv->stats.recvRunts++;
-		ERROUT(EINVAL);
-	}
-	if (m->m_len < iphlen + grelen) {
-		if ((m = m_pullup(m, iphlen + grelen)) == NULL) {
+		iphlen = ip->ip_hl << 2;
+		if (m->m_len < iphlen + sizeof(*gre)) {
+			if ((m = m_pullup(m, iphlen + sizeof(*gre))) == NULL) {
+				priv->stats.memoryFailures++;
+				ERROUT(ENOBUFS);
+			}
+			ip = mtod(m, const struct ip *);
+		}
+		gre = (const struct greheader *)((const u_char *)ip + iphlen);
+		grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck);
+		if (m->m_pkthdr.len < iphlen + grelen) {
+			priv->stats.recvRunts++;
+			ERROUT(EINVAL);
+		}
+		if (m->m_len < iphlen + grelen) {
+			if ((m = m_pullup(m, iphlen + grelen)) == NULL) {
+				priv->stats.memoryFailures++;
+				ERROUT(ENOBUFS);
+			}
+			ip = mtod(m, const struct ip *);
+			gre = (const struct greheader *)((const u_char *)ip + iphlen);
+		}
+	} else {
+	    /* There is no IPv4 header */
+
+		/* Sanity check packet length */
+		if (m->m_pkthdr.len < sizeof(*gre)) {
+			priv->stats.recvRunts++;
+			ERROUT(EINVAL);
+		}
+
+		/* Safely pull up the complete GRE headers */
+		if (m->m_len < sizeof(*gre)
+		    && (m = m_pullup(m, sizeof(*gre))) == NULL) {
 			priv->stats.memoryFailures++;
 			ERROUT(ENOBUFS);
 		}
-		ip = mtod(m, const struct ip *);
-		gre = (const struct greheader *)((const u_char *)ip + iphlen);
+		iphlen = 0;
+		gre = mtod(m, const struct greheader *);
+		grelen = sizeof(*gre) + sizeof(u_int32_t) * (gre->hasSeq + gre->hasAck);
+		if (m->m_pkthdr.len < grelen) {
+			priv->stats.recvRunts++;
+			ERROUT(EINVAL);
+		}
+		if (m->m_len < grelen) {
+			if ((m = m_pullup(m, grelen)) == NULL) {
+				priv->stats.memoryFailures++;
+				ERROUT(ENOBUFS);
+			}
+			gre = mtod(m, const struct greheader *);
+		}
+		
 	}
 
 	/* Sanity check packet length and GRE header bits */


More information about the freebsd-net mailing list