List Info

Thread: rfc: gre over udp




rfc: gre over udp
user name
2006-08-26 07:18:04
I need to tunnel packets through NAT routers to a tunnel
concentrator at
my office.  To that end, I am extending gre(4) to put tunnel
packets into
UDP datagrams.  I have attached a patch that contains my
work in progress.
I request your feedback.

In UDP mode, gre(4) puts a GRE header onto transmitted
packets, and hands
them to a UDP socket for transmission.  That is, the
encapsulation looks
like IP+UDP+GRE+encapsulated packet.

There are two ways to set up a UDP gre(4) instance.  One way
is to tell
the source and destination IP+port to gre(4), and let gre(4)
create
the socket:

# ifconfig gre0 create link2
# ifconfig gre0 tunnel 192.168.1.107,1025 192.168.1.101,1025
# ifconfig gre0 inet 192.168.49.2 192.168.49.1
# ifconfig gre0
gre0:
flags=d051<UP,POINTOPOINT,RUNNING,LINK0,LINK2,MULTICAST&g
t; mtu 1476
        tunnel inet 192.168.1.107,1025 -->
192.168.1.101,1025
        inet 192.168.49.2 -> 192.168.49.1 netmask
0xffffff00
        inet6 fe80::202:6fff:fe20:f62e%gre0 ->  prefixlen
64 scopeid 0x6

Note that to specify the UDP port number, some ifconfig(8)
changes
were necessary.  Those are in the patch.

The other way to create a UDP instance is for userland to
"delegate" a
UDP socket to the kernel.  I have only started to program
that feature;
see case GRESSOCK in gre_ioctl().  I intend to use this
feature in a
server that will run on the tunnel concentrator,
authenticating remote
tunnel endpoints and setting up tunnel privacy (perhaps
using IPSec)
before delegating the socket to the tunnel interface.

Dave

-- 
David Young             OJC Technologies
dyoungojctech.com      Urbana, IL * (217) 278-3933
Index: sys/net/if_gre.c
============================================================
=======
RCS file: /cvsroot/src/sys/net/if_gre.c,v
retrieving revision 1.61
diff -u -p -u -p -r1.61 if_gre.c
--- sys/net/if_gre.c	23 Jul 2006 22:06:12 -0000	1.61
+++ sys/net/if_gre.c	26 Aug 2006 07:11:14 -0000
 -56,11
+56,14  __KERNEL_RCSID(0, "$NetBSD: if_gre.c,v 1
 
 #ifdef INET
 #include <sys/param.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
 #include <sys/malloc.h>
 #include <sys/mbuf.h>
 #include <sys/proc.h>
 #include <sys/protosw.h>
 #include <sys/socket.h>
+#include <sys/socketvar.h>
 #include <sys/ioctl.h>
 #include <sys/queue.h>
 #if __NetBSD__
 -68,6
+71,8  __KERNEL_RCSID(0, "$NetBSD: if_gre.c,v 1
 #include <sys/kauth.h>
 #endif
 
+#include <sys/kthread.h>
+
 #include <machine/cpu.h>
 
 #include <net/ethertypes.h>
 -126,6
+131,42  static int	gre_ioctl(struct ifnet *, u_l
 
 static int	gre_compute_route(struct gre_softc *sc);
 
+static int gre_getsockname(struct socket *, struct mbuf *,
struct lwp *);
+#ifdef GRESSOCK
+static int gre_getpeername(struct socket *, struct mbuf *,
struct lwp *);
+static int gre_getnames(struct socket *, struct lwp *,
struct sockaddr_in *,
+    struct sockaddr_in *);
+#endif /* GRESSOCK */
+
+static void
+gre_stop(int *running)
+{
+	*running = 0;
+	wakeup(running);
+}
+
+static void
+gre_join(int *running)
+{
+	int s;
+
+	s = splnet();
+	while (*running != 0) {
+		splx(s);
+		tsleep(running, PSOCK, "grejoin", 0);
+		s = splnet();
+	}
+	splx(s);
+}
+
+static void
+gre_wakeup(int *waitchan)
+{
+	printf("%s: enter\n", __func__);
+	*waitchan = 1;
+	wakeup(waitchan);
+}
+
 static int
 gre_clone_create(struct if_clone *ifc, int unit)
 {
 -146,7
+187,10  gre_clone_create(struct if_clone *ifc, i
 	sc->sc_if.if_output = gre_output;
 	sc->sc_if.if_ioctl = gre_ioctl;
 	sc->g_dst.s_addr = sc->g_src.s_addr = INADDR_ANY;
+	sc->g_dstport = sc->g_srcport = 0;
 	sc->g_proto = IPPROTO_GRE;
+	IFQ_SET_READY(&sc->sc_snd);
+	IFQ_SET_MAXLEN(&sc->sc_snd, IFQ_MAXLEN);
 	sc->sc_if.if_flags |= IFF_LINK0;
 	if_attach(&sc->sc_if);
 	if_alloc_sadl(&sc->sc_if);
 -167,11
+211,365  gre_clone_destroy(struct ifnet *ifp)
 	bpfdetach(ifp);
 #endif
 	if_detach(ifp);
+	gre_wakeup(&sc->sc_waitchan);
+	gre_join(&sc->sc_thread);
 	free(sc, M_DEVBUF);
 
 	return (0);
 }
 
+static void
+gre_receive(struct socket *so, caddr_t arg, int waitflag)
+{
+	struct gre_softc *sc = (struct gre_softc *)arg;
+
+	printf("%s: enter\n", __func__);
+
+	gre_wakeup(&sc->sc_waitchan);
+}
+
+static void
+gre_sodestroy(struct socket **sop)
+{
+	printf("%s: shutting down\n", __func__);
+	soshutdown(*sop, SHUT_RDWR);
+	printf("%s: closing\n", __func__);
+	soclose(*sop);
+	*sop = NULL;
+}
+
+static struct mbuf *
+gre_getsockmbuf(struct socket *so)
+{
+	struct mbuf *m;
+
+	m = m_get(M_WAIT, MT_SONAME);
+	if (m != NULL)
+		MCLAIM(m, so->so_mowner);
+	return m;
+}
+
+static void
+gre_upcallsetup(struct socket *so, caddr_t arg)
+{
+	/* XXX What if the kernel already set an upcall? */
+	so->so_upcallarg = arg;
+	so->so_upcall = gre_receive;
+	so->so_rcv.sb_flags |= SB_UPCALL;
+}
+
+static int
+gre_socreate1(struct gre_softc *sc, struct lwp *l, struct
gre_soparm *sp,
+    struct socket **sop)
+{
+	int rc;
+	struct mbuf *m;
+	struct sockaddr_in *sin;
+	struct socket *so;
+
+	printf("%s: enter\n", __func__);
+	rc = socreate(AF_INET, sop, SOCK_DGRAM, IPPROTO_UDP, l);
+	if (rc != 0) {
+		printf("%s: socreate failed\n", __func__);
+		return rc;
+	}
+
+	so = *sop;
+
+	gre_upcallsetup(so, (caddr_t)sc);
+	if ((m = gre_getsockmbuf(so)) == NULL) {
+		rc = ENOBUFS;
+		goto out;
+	}
+	sin = mtod(m, struct sockaddr_in *);
+	sin->sin_len = m->m_len = sizeof(struct
sockaddr_in);
+	sin->sin_family = AF_INET;
+	sin->sin_addr = sc->g_src;
+	sin->sin_port = sc->g_srcport;
+
+	printf("%s: bind 0x%08" PRIx32 " port
%d\n", __func__,
+	    sin->sin_addr.s_addr, ntohs(sin->sin_port));
+	if ((rc = sobind(so, m, l)) != 0) {
+		printf("%s: sobind failed\n", __func__);
+		goto out;
+	}
+
+	if (sc->g_srcport == 0) {
+		if (gre_getsockname(so, m, l) != 0) {
+			printf("%s: gre_getsockname failed\n",
__func__);
+			goto out;
+		}
+		sc->g_srcport = sin->sin_port;
+	}
+
+	sin->sin_addr = sc->g_dst;
+	sin->sin_port = sc->g_dstport;
+
+	rc = soconnect(so, m, l);
+
+	if (rc != 0) {
+		printf("%s: soconnect failed\n", __func__);
+		goto out;
+	}
+
+	*mtod(m, int *) = ip_gre_ttl;
+	rc = (*so->so_proto->pr_ctloutput)(PRCO_SETOPT, so,
IPPROTO_IP, IP_TTL,
+	    &m);
+	m = NULL;
+	if (rc != 0) {
+		printf("%s: setopt ttl failed\n", __func__);
+		rc = 0;
+	}
+out:
+	m_freem(m);
+
+	if (rc != 0)
+		gre_sodestroy(sop);
+	else
+		*sp = sc->sc_sp;
+
+	return rc;
+}
+
+static void
+gre_thread1(struct gre_softc *sc, struct lwp *l)
+{
+	int flags, rc, s;
+	const struct gre_h *gh;
+	struct ifnet *ifp = &sc->sc_if;
+	struct mbuf *m;
+	struct socket *so;
+	struct uio uio;
+	struct gre_soparm sp;
+
+	printf("%s: enter\n", __func__);
+	s = splnet();
+
+	if (gre_socreate1(sc, l, &sp, &so) != 0)
+		goto out;
+
+	memset(&sp, 0, sizeof(sp));
+	memset(&uio, 0, sizeof(uio));
+
+	ifp->if_flags |= IFF_RUNNING;
+
+	for (;;) {
+		printf("%s: sleeping\n", __func__);
+		while (sc->sc_waitchan == 0) {
+			splx(s);
+			tsleep(&sc->sc_waitchan, PSOCK,
"grewait", 0);
+			s = splnet();
+		}
+		sc->sc_waitchan = 0;
+		printf("%s: woke\n", __func__);
+		if ((ifp->if_flags & IFF_UP) != IFF_UP) {
+			printf("%s: not up & running;
exiting\n", __func__);
+			break;
+		}
+		if (sc->g_proto != IPPROTO_UDP) {
+			printf("%s: not udp; exiting\n", __func__);
+			break;
+		}
+		/* XXX optimize */ 
+		if (memcmp(&sp, &sc->sc_sp, sizeof(sp)) != 0)
{
+			printf("%s: parameters changed\n",
__func__);
+#ifdef GRESSOCK
+			if (sp.sp_fp != NULL) {
+				FILE_UNUSE(sp.sp_fp, NULL);
+				sp.sp_fp = NULL;
+				so = NULL;
+			} else
+#endif /* GRESSOCK */
+				gre_sodestroy(&so);
+#ifdef GRESSOCK
+			if (sc->sc_fp != NULL) {
+				so = (struct socket *)sc->sc_fp->f_data;
+				gre_upcallsetup(so, (caddr_t)sc);
+				sp = sc->sc_sp;
+				FILE_USE(sp.sp_fp);
+			} else
+#endif /* GRESSOCK */
+			if (gre_socreate1(sc, l, &sp, &so) != 0)
+				goto out;
+		}
+		for (;;) {
+			flags = MSG_DONTWAIT;
+			uio.uio_resid = 1000000;
+			rc = (*so->so_receive)(so, NULL, &uio, &m,
NULL,
+			    &flags);
+			/* TBD Back off if ECONNREFUSED (indicates
+			 * ICMP Port Unreachable)?
+			 */
+			if (rc == EWOULDBLOCK) {
+				printf("%s: so_receive EWOULDBLOCK\n",
+				    __func__);
+				break;
+			} else if (rc != 0 || m == NULL) {
+				printf("%s: rc %d m %p\n",
+				    ifp->if_xname, rc, (void *)m);
+				break;
+			}
+			if (m->m_len < sizeof(*gh) &&
+			    (m = m_pullup(m, sizeof(*gh))) == NULL) {
+				printf("%s: m_pullup failed\n", __func__);
+				continue;
+			}
+			gh = mtod(m, const struct gre_h *);
+
+			if (gre_input3(sc, m, 0, IPPROTO_GRE, gh) == 0) {
+				printf("%s: dropping unsupported\n",
__func__);
+				m_freem(m);
+			}
+		}
+		for (;;) {
+			IF_DEQUEUE(&sc->sc_snd, m);
+			if (m == NULL)
+				break;
+			printf("%s: dequeue\n", __func__);
+			if ((so->so_state & SS_ISCONNECTED) == 0) {
+				printf("%s: not connected\n", __func__);
+				m_freem(m);
+				continue;
+			}
+			rc = (*so->so_send)(so, NULL, NULL, m, NULL, 0, l);
+			/* XXX handle ENOBUFS? */
+			if (rc != 0)
+				printf("%s: so_send failed\n", __func__);
+		}
+	}
+#ifdef GRESSOCK
+	if (sp.sp_fp != NULL) {
+		FILE_UNUSE(sp.sp_fp, NULL);
+		sp.sp_fp = NULL;
+	} else
+#endif /* GRESSOCK */
+		gre_sodestroy(&so);
+out:
+	printf("%s: stopping\n", __func__);
+	if (sc->g_proto == IPPROTO_UDP)
+		ifp->if_flags &= ~IFF_RUNNING;
+	IFQ_PURGE(&sc->sc_snd);
+	gre_stop(&sc->sc_thread);
+	/* must not touch sc after this! */
+	printf("%s: restore ipl\n", __func__);
+	splx(s);
+}
+
+static void
+gre_thread(void *arg)
+{
+	struct gre_softc *sc = (struct gre_softc *)arg;
+
+	gre_thread1(sc, curlwp);
+	/* must not touch sc after this! */
+	kthread_exit(0);
+}
+
+int
+gre_input3(struct gre_softc *sc, struct mbuf *m, int hlen,
u_char proto,
+    const struct gre_h *gh)
+{
+	u_int16_t flags;
+#if NBPFILTER > 0
+	u_int32_t af = AF_INET;		/* af passed to BPF tap */
+#endif
+	int s, isr;
+	struct ifqueue *ifq;
+
+	sc->sc_if.if_ipackets++;
+	sc->sc_if.if_ibytes += m->m_pkthdr.len;
+
+	switch (proto) {
+	case IPPROTO_GRE:
+		hlen += sizeof(struct gre_h);
+
+		/* process GRE flags as packet can be of variable len */
+		flags = ntohs(gh->flags);
+
+		/* Checksum & Offset are present */
+		if ((flags & GRE_CP) | (flags & GRE_RP))
+			hlen += 4;
+		/* We don't support routing fields (variable length) */
+		if (flags & GRE_RP)
+			return (0);
+		if (flags & GRE_KP)
+			hlen += 4;
+		if (flags & GRE_SP)
+			hlen += 4;
+
+		switch (ntohs(gh->ptype)) { /* ethertypes */
+		case ETHERTYPE_IP: /* shouldn't need a schednetisr(), as
*/
+			ifq = &ipintrq;          /* we are in ip_input */
+			isr = NETISR_IP;
+			break;
+#ifdef NS
+		case ETHERTYPE_NS:
+			ifq = &nsintrq;
+			isr = NETISR_NS;
+#if NBPFILTER > 0
+			af = AF_NS;
+#endif
+			break;
+#endif
+#ifdef NETATALK
+		case ETHERTYPE_ATALK:
+			ifq = &atintrq1;
+			isr = NETISR_ATALK;
+#if NBPFILTER > 0
+			af = AF_APPLETALK;
+#endif
+			break;
+#endif
+#ifdef INET6
+		case ETHERTYPE_IPV6:
+#ifdef GRE_DEBUG
+			printf("%s: IPv6 packet\n", __func__);
+#endif
+			ifq = &ip6intrq;
+			isr = NETISR_IPV6;
+#if NBPFILTER > 0
+			af = AF_INET6;
+#endif
+			break;
+#endif
+		default:	   /* others not yet supported */
+			printf("%s: unhandled ethertype 0x%04x\n",
__func__,
+			    ntohs(gh->ptype));
+			return (0);
+		}
+		break;
+	default:
+		/* others not yet supported */
+		return (0);
+	}
+
+	if (hlen > m->m_pkthdr.len) {
+		m_freem(m);
+		return (EINVAL);
+	}
+	m_adj(m, hlen);
+
+#if NBPFILTER > 0
+	if (sc->sc_if.if_bpf != NULL)
+		bpf_mtap_af(sc->sc_if.if_bpf, af, m);
+#endif /*NBPFILTER > 0*/
+
+	m->m_pkthdr.rcvif = &sc->sc_if;
+
+	s = splnet();		/* possible */
+	if (IF_QFULL(ifq)) {
+		IF_DROP(ifq);
+		m_freem(m);
+	} else {
+		IF_ENQUEUE(ifq, m);
+	}
+	/* we need schednetisr since the address family may change
*/
+	schednetisr(isr);
+	splx(s);
+
+	return (1);	/* packet is done, no further processing
needed */
+}
+
 /*
  * The output routine. Takes a packet and encapsulates it
in the protocol
  * given by sc->g_proto. See also RFC 1701 and RFC 2004
 -180,10
+578,11  static int
 gre_output(struct ifnet *ifp, struct mbuf *m, struct
sockaddr *dst,
 	   struct rtentry *rt)
 {
-	int error = 0;
+	int error = 0, hlen;
 	struct gre_softc *sc = ifp->if_softc;
-	struct greip *gh;
-	struct ip *ip;
+	struct greip *gi;
+	struct gre_h *gh;
+	struct ip *eip, *ip;
 	u_int8_t ip_tos = 0;
 	u_int16_t etype = 0;
 	struct mobile_h mob_h;
 -195,7
+594,7  gre_output(struct ifnet *ifp, struct mbu
 		goto end;
 	}
 
-	gh = NULL;
+	gi = NULL;
 	ip = NULL;
 
 #if NBPFILTER >0
 -205,11
+604,16  gre_output(struct ifnet *ifp, struct mbu
 
 	m->m_flags &= ~(M_BCAST|M_MCAST);
 
-	if (sc->g_proto == IPPROTO_MOBILE) {
+	switch (sc->g_proto) {
+	case IPPROTO_MOBILE:
 		if (dst->sa_family == AF_INET) {
-			struct mbuf *m0;
 			int msiz;
 
+			if (M_UNWRITABLE(m, sizeof(*ip)) &&
+			    (m = m_pullup(m, sizeof(*ip))) == NULL) {
+				error = ENOBUFS;
+				goto end;
+			}
 			ip = mtod(m, struct ip *);
 
 			memset(&mob_h, 0, MOB_H_SIZ_L);
 -233,31
+637,16  gre_output(struct ifnet *ifp, struct mbu
 			HTONS(mob_h.proto);
 			mob_h.hcrc = gre_in_cksum((u_int16_t *)&mob_h,
msiz);
 
-			if ((m->m_data - msiz) < m->m_pktdat) {
-				/* need new mbuf */
-				MGETHDR(m0, M_DONTWAIT, MT_HEADER);
-				if (m0 == NULL) {
-					IF_DROP(&ifp->if_snd);
-					m_freem(m);
-					error = ENOBUFS;
-					goto end;
-				}
-				m0->m_next = m;
-				m->m_data += sizeof(struct ip);
-				m->m_len -= sizeof(struct ip);
-				m0->m_pkthdr.len = m->m_pkthdr.len + msiz;
-				m0->m_len = msiz + sizeof(struct ip);
-				m0->m_data += max_linkhdr;
-				memcpy(mtod(m0, caddr_t), (caddr_t)ip,
-				       sizeof(struct ip));
-				m = m0;
-			} else {  /* we have some space left in the old one */
-				m->m_data -= msiz;
-				m->m_len += msiz;
-				m->m_pkthdr.len += msiz;
-				memmove(mtod(m, caddr_t), ip,
-					sizeof(struct ip));
+			M_PREPEND(m, msiz, M_DONTWAIT);
+			if (m == NULL) {
+				error = ENOBUFS;
+				goto end;
 			}
+			/* XXX Assuming that ip does not dangle after
+			 * M_PREPEND.  In practice, that's true, but
+			 * that's in M_PREPEND's contract.
+			 */
+			memmove(mtod(m, caddr_t), ip, sizeof(*ip));
 			ip = mtod(m, struct ip *);
 			memcpy((caddr_t)(ip + 1), &mob_h, (unsigned)msiz);
 			ip->ip_len = htons(ntohs(ip->ip_len) + msiz);
 -267,10
+656,11  gre_output(struct ifnet *ifp, struct mbu
 			error = EINVAL;
 			goto end;
 		}
-	} else if (sc->g_proto == IPPROTO_GRE) {
+		break;
+	case IPPROTO_UDP:
+	case IPPROTO_GRE:
 #ifdef GRE_DEBUG
-               printf( "start gre_output/GRE,
dst->sa_family=%d\n",
-                        dst->sa_family );
+               printf("%s:
dst->sa_family=%d\n", __func__,
dst->sa_family);
 #endif
 		switch (dst->sa_family) {
 		case AF_INET:
 -299,52
+689,184  gre_output(struct ifnet *ifp, struct mbu
 			error = EAFNOSUPPORT;
 			goto end;
 		}
-		M_PREPEND(m, sizeof(struct greip), M_DONTWAIT);
-	} else {
+		break;
+	default:
 		IF_DROP(&ifp->if_snd);
 		m_freem(m);
 		error = EINVAL;
 		goto end;
 	}
 
-	if (m == NULL) {	/* impossible */
+	switch (sc->g_proto) {
+	case IPPROTO_GRE:
+		hlen = sizeof(struct greip);
+		break;
+	case IPPROTO_UDP:
+		hlen = sizeof(struct gre_h);
+		break;
+	default:
+		hlen = 0;
+		break;
+	}
+
+	M_PREPEND(m, hlen, M_DONTWAIT);
+
+	if (m == NULL) {
 		IF_DROP(&ifp->if_snd);
 		error = ENOBUFS;
 		goto end;
 	}
 
-	gh = mtod(m, struct greip *);
-	if (sc->g_proto == IPPROTO_GRE) {
+	switch (sc->g_proto) {
+	case IPPROTO_UDP:
+		gh = mtod(m, struct gre_h *);
+		memset(gh, 0, sizeof(*gh));
+		gh->ptype = htons(etype);
+		/* XXX Need to handle IP ToS.  Look at how I handle IP
TTL. */
+		break;
+	case IPPROTO_GRE:
+		gi = mtod(m, struct greip *);
+		gh = &gi->gi_g;
+		eip = &gi->gi_i;
 		/* we don't have any GRE flags for now */
-
-		memset((void *)&gh->gi_g, 0, sizeof(struct
gre_h));
-		gh->gi_ptype = htons(etype);
-	}
-
-	gh->gi_pr = sc->g_proto;
-	if (sc->g_proto != IPPROTO_MOBILE) {
-		gh->gi_src = sc->g_src;
-		gh->gi_dst = sc->g_dst;
-		((struct ip*)gh)->ip_hl = (sizeof(struct ip)) >>
2;
-		((struct ip*)gh)->ip_ttl = ip_gre_ttl;
-		((struct ip*)gh)->ip_tos = ip_tos;
-		gh->gi_len = htons(m->m_pkthdr.len);
+		memset(gh, 0, sizeof(*gh));
+		gh->ptype = htons(etype);
+		eip->ip_src = sc->g_src;
+		eip->ip_dst = sc->g_dst;
+		eip->ip_hl = (sizeof(struct ip)) >> 2;
+		eip->ip_ttl = ip_gre_ttl;
+		eip->ip_tos = ip_tos;
+		eip->ip_len = htons(m->m_pkthdr.len);
+		eip->ip_p = sc->g_proto;
+		break;
+	case IPPROTO_MOBILE:
+		eip = mtod(m, struct ip *);
+		eip->ip_p = sc->g_proto;
+		break;
+	default:
+		error = EPROTONOSUPPORT;
+		m_freem(m);
+		goto end;
 	}
 
 	ifp->if_opackets++;
 	ifp->if_obytes += m->m_pkthdr.len;
+
 	/* send it off */
-	error = ip_output(m, NULL, &sc->route, 0,
-	    (struct ip_moptions *)NULL, (struct socket *)NULL);
+	if (sc->g_proto == IPPROTO_UDP) {
+		if (IF_QFULL(&sc->sc_snd)) {
+			IF_DROP(&sc->sc_snd);
+			error = ENOBUFS;
+			m_freem(m);
+		} else {
+			IF_ENQUEUE(&sc->sc_snd, m);
+			gre_wakeup(&sc->sc_waitchan);
+			error = 0;
+		}
+	} else {
+		error = ip_output(m, NULL, &sc->route, 0,
+		    (struct ip_moptions *)NULL, (struct socket *)NULL);
+	}
   end:
 	if (error)
 		ifp->if_oerrors++;
 	return (error);
 }
 
+/* Must be called at IPL_NET. */
+static int
+gre_kick(struct gre_softc *sc)
+{
+	int rc;
+	struct ifnet *ifp = &sc->sc_if;
+
+	if (sc->g_proto == IPPROTO_UDP &&
(ifp->if_flags & IFF_UP) == IFF_UP &&
+	    !sc->sc_thread) {
+		sc->sc_thread = 1;
+		rc = kthread_create1(gre_thread, (void *)sc, NULL,
+		    ifp->if_xname);
+		if (rc != 0)
+			gre_stop(&sc->sc_thread);
+		return rc;
+	} else {
+		gre_wakeup(&sc->sc_waitchan);
+		return 0;
+	}
+}
+
+static int
+gre_getname(struct socket *so, int req, struct mbuf *nam,
struct lwp *l)
+{
+	int s, error;
+
+	printf("%s: enter\n", __func__);
+	s = splsoftnet();
+	error = (*so->so_proto->pr_usrreq)(so, req, (struct
mbuf *)0,
+	    nam, (struct mbuf *)0, l);
+	splx(s);
+	return error;
+}
+
+static int
+gre_getsockname(struct socket *so, struct mbuf *nam, struct
lwp *l)
+{
+	printf("%s: enter\n", __func__);
+	return gre_getname(so, PRU_SOCKADDR, nam, l);
+}
+
+#ifdef GRESSOCK
+static int
+gre_getpeername(struct socket *so, struct mbuf *nam, struct
lwp *l)
+{
+	printf("%s: enter\n", __func__);
+	return gre_getname(so, PRU_PEERADDR, nam, l);
+}
+
+static int
+gre_getnames(struct socket *so, struct lwp *l, struct
sockaddr_in *src,
+    struct sockaddr_in *dst)
+{
+	struct mbuf *m;
+	struct sockaddr_in *sin;
+	int rc;
+
+	if ((m = gre_getsockmbuf(so)) == NULL)
+		return ENOBUFS;
+
+	sin = mtod(m, struct sockaddr_in *);
+
+	if ((rc = gre_getsockname(so, m, l)) != 0)
+		goto out;
+	if (sin->sin_family != AF_INET) {
+		rc = EAFNOSUPPORT;
+		goto out;
+	}
+	*src = *sin;
+
+	if ((rc = gre_getpeername(so, m, l)) != 0)
+		goto out;
+	if (sin->sin_family != AF_INET) {
+		rc = EAFNOSUPPORT;
+		goto out;
+	}
+	*dst = *sin;
+
+out:
+	m_freem(m);
+	return rc;
+}
+#endif /* GRESSOCK */
+
 static int
 gre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
 {
+	u_char oproto;
+#ifdef GRESSOCK
+	struct file *fp, *ofp;
+	struct socket *so;
+	struct sockaddr_in dst, src;
+#endif /* GRESSOCK */
+	struct proc *p = curproc;	/* XXX */
 	struct lwp *l = curlwp;	/* XXX */
 	struct ifreq *ifr = (struct ifreq *)data;
 	struct if_laddrreq *lifr = (struct if_laddrreq *)data;
 -360,6
+882,8  gre_ioctl(struct ifnet *ifp, u_long cmd,
 	case GRESPROTO:
 	case GRESADDRD:
 	case GRESADDRS:
+	case GRESSOCK:
+	case GREDSOCK:
 	case SIOCSLIFPHYADDR:
 	case SIOCDIFPHYADDR:
 		if ((error = kauth_authorize_generic(l->l_cred,
 -375,14
+899,28  gre_ioctl(struct ifnet *ifp, u_long cmd,
 	switch (cmd) {
 	case SIOCSIFADDR:
 		ifp->if_flags |= IFF_UP;
+		error = gre_kick(sc);
 		break;
 	case SIOCSIFDSTADDR:
 		break;
 	case SIOCSIFFLAGS:
-		if ((ifr->ifr_flags & IFF_LINK0) != 0)
+		oproto = sc->g_proto;
+		switch (ifr->ifr_flags & (IFF_LINK0|IFF_LINK2)) {
+		case IFF_LINK0|IFF_LINK2:
+			sc->g_proto = IPPROTO_UDP;
+			if (oproto != IPPROTO_UDP)
+				ifp->if_flags &= ~IFF_RUNNING;
+			error = gre_kick(sc);
+			break;
+		case IFF_LINK0:
 			sc->g_proto = IPPROTO_GRE;
-		else
+			gre_wakeup(&sc->sc_waitchan);
+			goto recompute;
+		case 0:
 			sc->g_proto = IPPROTO_MOBILE;
+			gre_wakeup(&sc->sc_waitchan);
+			goto recompute;
+		}
 		break;
 	case SIOCSIFMTU:
 		if (ifr->ifr_mtu < 576) {
 -415,14
+953,22  gre_ioctl(struct ifnet *ifp, u_long cmd,
 		}
 		break;
 	case GRESPROTO:
+		oproto = sc->g_proto;
 		sc->g_proto = ifr->ifr_flags;
 		switch (sc->g_proto) {
+		case IPPROTO_UDP:
+			ifp->if_flags |= IFF_LINK0|IFF_LINK2;
+			if (oproto != IPPROTO_UDP)
+				ifp->if_flags &= ~IFF_RUNNING;
+			error = gre_kick(sc);
+			break;
 		case IPPROTO_GRE:
 			ifp->if_flags |= IFF_LINK0;
-			break;
+			ifp->if_flags &= ~IFF_LINK2;
+			goto recompute;
 		case IPPROTO_MOBILE:
-			ifp->if_flags &= ~IFF_LINK0;
-			break;
+			ifp->if_flags &= ~(IFF_LINK0|IFF_LINK2);
+			goto recompute;
 		default:
 			error = EPROTONOSUPPORT;
 			break;
 -438,16
+984,36  gre_ioctl(struct ifnet *ifp, u_long cmd,
 		 * to the remote end and mark if as up
 		 */
 		sa = &ifr->ifr_addr;
-		if (cmd == GRESADDRS)
+		if (cmd == GRESADDRS) {
 			sc->g_src = (satosin(sa))->sin_addr;
-		if (cmd == GRESADDRD)
+			sc->g_srcport = satosin(sa)->sin_port;
+		}
+		if (cmd == GRESADDRD) {
+			if (sc->g_proto == IPPROTO_UDP &&
+			    satosin(sa)->sin_port == 0) {
+				error = EINVAL;
+				break;
+			}
 			sc->g_dst = (satosin(sa))->sin_addr;
+			sc->g_dstport = satosin(sa)->sin_port;
+		}
 	recompute:
-		if ((sc->g_src.s_addr != INADDR_ANY) &&
-		    (sc->g_dst.s_addr != INADDR_ANY)) {
-			if (sc->route.ro_rt != 0) /* free old route */
+		if (sc->g_proto == IPPROTO_UDP ||
+		    (sc->g_src.s_addr != INADDR_ANY &&
+		     sc->g_dst.s_addr != INADDR_ANY)) {
+#ifdef GRESSOCK
+			if (sc->sc_fp != NULL) {
+				FILE_UNUSE(sc->sc_fp, NULL);
+				sc->sc_fp = NULL;
+			}
+#endif /* GRESSOCK */
+			if (sc->route.ro_rt != NULL) {
 				RTFREE(sc->route.ro_rt);
-			if (gre_compute_route(sc) == 0)
+				sc->route.ro_rt = NULL;
+			}
+			if (sc->g_proto == IPPROTO_UDP)
+				error = gre_kick(sc);
+			else if (gre_compute_route(sc) == 0)
 				ifp->if_flags |= IFF_RUNNING;
 			else
 				ifp->if_flags &= ~IFF_RUNNING;
 -469,6
+1035,47  gre_ioctl(struct ifnet *ifp, u_long cmd,
 		sa = sintosa(&si);
 		ifr->ifr_addr = *sa;
 		break;
+#ifdef GRESSOCK
+	case GREDSOCK:
+		if (sc->g_proto != IPPROTO_UDP)
+			return EINVAL;
+		FILE_UNUSE(sc->sc_fp, NULL);
+		sc->sc_fp = NULL;
+		error = gre_kick(sc);
+		break;
+	case GRESSOCK:
+		if (sc->g_proto != IPPROTO_UDP)
+			return EINVAL;
+		/* getsock() will use the descriptor for us */
+		if ((error = getsock(p->p_fd, (int)ifr->ifr_value,
&fp)) != 0)
+			break;
+		so = (struct socket *)fp->f_data;
+		if (so->so_type != SOCK_DGRAM) {
+			FILE_UNUSE(fp, NULL);
+			error = EINVAL;
+			break;
+		}
+		/* check address */
+		if ((error = gre_getnames(so, curlwp, &src,
&dst)) != 0) {
+			FILE_UNUSE(fp, NULL);
+			break;
+		}
+
+		ofp = sc->sc_fp;
+		sc->sc_fp = fp;
+		if ((error = gre_kick(sc)) != 0) {
+			FILE_UNUSE(fp, NULL);
+			sc->sc_fp = ofp;
+			break;
+		}
+		sc->g_src = src.sin_addr;
+		sc->g_srcport = src.sin_port;
+		sc->g_dst = dst.sin_addr;
+		sc->g_dstport = dst.sin_port;
+		if (ofp != NULL)
+			FILE_UNUSE(ofp, NULL);
+		break;
+#endif /* GRESSOCK */
 	case SIOCSLIFPHYADDR:
 		if (lifr->addr.ss_family != AF_INET ||
 		    lifr->dstaddr.ss_family != AF_INET) {
 -480,14
+1087,15  gre_ioctl(struct ifnet *ifp, u_long cmd,
 			error = EINVAL;
 			break;
 		}
-		sc->g_src = (satosin((struct sockadrr
*)&lifr->addr))->sin_addr;
-		sc->g_dst =
-		    (satosin((struct sockadrr
*)&lifr->dstaddr))->sin_addr;
+		sc->g_src = satosin(&lifr->addr)->sin_addr;
+		sc->g_dst =
satosin(&lifr->dstaddr)->sin_addr;
+		sc->g_srcport =
satosin(&lifr->addr)->sin_port;
+		sc->g_dstport =
satosin(&lifr->dstaddr)->sin_port;
 		goto recompute;
 	case SIOCDIFPHYADDR:
 		sc->g_src.s_addr = INADDR_ANY;
 		sc->g_dst.s_addr = INADDR_ANY;
-		break;
+		goto recompute;
 	case SIOCGLIFPHYADDR:
 		if (sc->g_src.s_addr == INADDR_ANY ||
 		    sc->g_dst.s_addr == INADDR_ANY) {
 -497,16
+1105,19  gre_ioctl(struct ifnet *ifp, u_long cmd,
 		memset(&si, 0, sizeof(si));
 		si.sin_family = AF_INET;
 		si.sin_len = sizeof(struct sockaddr_in);
-		si.sin_addr.s_addr = sc->g_src.s_addr;
+		si.sin_addr = sc->g_src;
+		if (sc->g_proto == IPPROTO_UDP)
+			si.sin_port = sc->g_srcport;
 		memcpy(&lifr->addr, &si, sizeof(si));
-		si.sin_addr.s_addr = sc->g_dst.s_addr;
+		si.sin_addr = sc->g_dst;
+		if (sc->g_proto == IPPROTO_UDP)
+			si.sin_port = sc->g_dstport;
 		memcpy(&lifr->dstaddr, &si, sizeof(si));
 		break;
 	default:
 		error = EINVAL;
 		break;
 	}
-
 	splx(s);
 	return (error);
 }
 -580,9
+1191,8  gre_compute_route(struct gre_softc *sc)
 		((struct sockaddr_in *)&ro->ro_dst)->sin_addr =
sc->g_dst;
 
 #ifdef DIAGNOSTIC
-	printf(", choosing %s with gateway %s",
ro->ro_rt->rt_ifp->if_xname,
+	printf(", choosing %s with gateway %s\n",
ro->ro_rt->rt_ifp->if_xname,
 	    inet_ntoa(((struct sockaddr_in
*)(ro->ro_rt->rt_gateway))->sin_addr));
-	printf("\n");
 #endif
 
 	return 0;
Index: sys/net/if_gre.h
============================================================
=======
RCS file: /cvsroot/src/sys/net/if_gre.h,v
retrieving revision 1.16
diff -u -p -u -p -r1.16 if_gre.h
--- sys/net/if_gre.h	11 Dec 2005 23:05:25 -0000	1.16
+++ sys/net/if_gre.h	26 Aug 2006 07:11:14 -0000
 -41,18
+41,37 
 
 #include <sys/queue.h>
 
+#if 1
+#define GRESSOCK	_IOW('i' , 107, struct ifreq)
+#define GREDSOCK	_IOW('i' , 108, struct ifreq)
+#endif
+
+struct gre_soparm {
+	struct in_addr	sp_src;		/* source address of gre packets
*/
+	struct in_addr	sp_dst;		/* destination address of gre
packets */
+	in_port_t	sp_srcport;	/* source port of gre packets */
+	in_port_t	sp_dstport;	/* destination port of gre packets
*/
+#ifdef GRESSOCK
+	struct file	*sp_fp;
+#endif /* GRESSOCK */
+};
+
 struct gre_softc {
-	struct ifnet sc_if;
+	struct ifnet		sc_if;
+	int			sc_waitchan;
+	int			sc_thread;
+	struct ifqueue		sc_snd;
+	struct gre_soparm	sc_sp;
 	LIST_ENTRY(gre_softc) sc_list;
-	int gre_unit;
-	int gre_flags;
-	struct in_addr g_src;	/* source address of gre packets */
-	struct in_addr g_dst;	/* destination address of gre
packets */
 	struct route route;	/* routing entry that determines,
where a
 				   encapsulated packet should go */
 	u_char g_proto;		/* protocol of encapsulator */
 };
-
+#define	g_src		sc_sp.sp_src
+#define	g_srcport	sc_sp.sp_srcport
+#define	g_dst		sc_sp.sp_dst
+#define	g_dstport	sc_sp.sp_dstport
+#define	sc_fp		sc_sp.sp_fp
 
 struct gre_h {
 	u_int16_t flags;	/* GRE flags */
 -152,6
+171,8  LIST_HEAD(gre_softc_head, gre_softc);
 extern struct gre_softc_head gre_softc_list;
 
 u_int16_t gre_in_cksum(u_short *, u_int);
+int gre_input3(struct gre_softc *, struct mbuf *, int,
u_char,
+    const struct gre_h *);
 #endif /* _KERNEL */
 
 #endif /* !_NET_IF_GRE_H_ */
Index: sys/netinet/ip_gre.c
============================================================
=======
RCS file: /cvsroot/src/sys/netinet/ip_gre.c,v
retrieving revision 1.40
diff -u -p -u -p -r1.40 ip_gre.c
--- sys/netinet/ip_gre.c	28 Jul 2006 17:34:13 -0000	1.40
+++ sys/netinet/ip_gre.c	26 Aug 2006 07:11:14 -0000
 -147,13
+147,7  int
 gre_input2(struct mbuf *m, int hlen, u_char proto)
 {
 	const struct greip *gip;
-	int s, isr;
-	struct ifqueue *ifq;
 	struct gre_softc *sc;
-	u_int16_t flags;
-#if NBPFILTER > 0
-	u_int32_t af = AF_INET;		/* af passed to BPF tap */
-#endif
 
 	if ((sc = gre_lookup(m, proto)) == NULL) {
 		/* No matching tunnel or tunnel is down. */
 -167,97
+161,7  gre_input2(struct mbuf *m, int hlen, u_c
 	}
 	gip = mtod(m, const struct greip *);
 
-	sc->sc_if.if_ipackets++;
-	sc->sc_if.if_ibytes += m->m_pkthdr.len;
-
-	switch (proto) {
-	case IPPROTO_GRE:
-		hlen += sizeof(struct gre_h);
-
-		/* process GRE flags as packet can be of variable len */
-		flags = ntohs(gip->gi_flags);
-
-		/* Checksum & Offset are present */
-		if ((flags & GRE_CP) | (flags & GRE_RP))
-			hlen += 4;
-		/* We don't support routing fields (variable length) */
-		if (flags & GRE_RP)
-			return (0);
-		if (flags & GRE_KP)
-			hlen += 4;
-		if (flags & GRE_SP)
-			hlen += 4;
-
-		switch (ntohs(gip->gi_ptype)) { /* ethertypes */
-		case ETHERTYPE_IP: /* shouldn't need a schednetisr(), as
*/
-			ifq = &ipintrq;          /* we are in ip_input */
-			isr = NETISR_IP;
-			break;
-#ifdef NS
-		case ETHERTYPE_NS:
-			ifq = &nsintrq;
-			isr = NETISR_NS;
-#if NBPFILTER > 0
-			af = AF_NS;
-#endif
-			break;
-#endif
-#ifdef NETATALK
-		case ETHERTYPE_ATALK:
-			ifq = &atintrq1;
-			isr = NETISR_ATALK;
-#if NBPFILTER > 0
-			af = AF_APPLETALK;
-#endif
-			break;
-#endif
-#ifdef INET6
-		case ETHERTYPE_IPV6:
-#ifdef GRE_DEBUG
-			printf( "ip_gre.c/gre_input2: IPv6
packet\n" );
-#endif
-			ifq = &ip6intrq;
-			isr = NETISR_IPV6;
-#if NBPFILTER > 0
-			af = AF_INET6;
-#endif
-			break;
-#endif
-		default:	   /* others not yet supported */
-			printf( "ip_gre.c/gre_input2: unhandled ethertype
0x%04x\n", (int) ntohs(gip->gi_ptype) );
-			return (0);
-		}
-		break;
-	default:
-		/* others not yet supported */
-		return (0);
-	}
-
-	if (hlen > m->m_pkthdr.len) {
-		m_freem(m);
-		return (EINVAL);
-	}
-	m_adj(m, hlen);
-
-#if NBPFILTER > 0
-	if (sc->sc_if.if_bpf != NULL)
-		bpf_mtap_af(sc->sc_if.if_bpf, af, m);
-#endif /*NBPFILTER > 0*/
-
-	m->m_pkthdr.rcvif = &sc->sc_if;
-
-	s = splnet();		/* possible */
-	if (IF_QFULL(ifq)) {
-		IF_DROP(ifq);
-		m_freem(m);
-	} else {
-		IF_ENQUEUE(ifq, m);
-	}
-	/* we need schednetisr since the address family may change
*/
-	schednetisr(isr);
-	splx(s);
-
-	return (1);	/* packet is done, no further processing
needed */
+	return gre_input3(sc, m, hlen, proto, &gip->gi_g);
 }
 
 /*
 -273,6
+177,7  gre_mobile_input(struct mbuf *m, ...)
 	struct mobip_h *mip;
 	struct ifqueue *ifq;
 	struct gre_softc *sc;
+	uint8_t *hdr;
 	int hlen, s;
 	va_list ap;
 	int msiz;
 -293,6
+198,7  gre_mobile_input(struct mbuf *m, ...)
 			return;
 	}
 	ip = mtod(m, struct ip *);
+	/* XXX what if there are IP options? */
 	mip = mtod(m, struct mobip_h *);
 
 	sc->sc_if.if_ipackets++;
 -304,8
+210,8  gre_mobile_input(struct mbuf *m, ...)
 	} else
 		msiz = MOB_H_SIZ_S;
 
-	if (m->m_len < (ip->ip_hl << 2) + msiz) {
-		m = m_pullup(m, (ip->ip_hl << 2) + msiz);
+	if (M_UNWRITABLE(m, hlen + msiz)) {
+		m = m_pullup(m, hlen + msiz);
 		if (m == NULL)
 			return;
 		ip = mtod(m, struct ip *);
 -320,14
+226,14  gre_mobile_input(struct mbuf *m, ...)
 		return;
 	}
 
-	memmove(ip + (ip->ip_hl << 2), ip + (ip->ip_hl
<< 2) + msiz,
-		m->m_len - msiz - (ip->ip_hl << 2));
+	hdr = mtod(m, uint8_t *);
+	memmove(hdr + hlen, hdr + hlen + msiz, m->m_len - msiz
- hlen);
 	m->m_len -= msiz;
 	ip->ip_len = htons(ntohs(ip->ip_len) - msiz);
 	m->m_pkthdr.len -= msiz;
 
 	ip->ip_sum = 0;
-	ip->ip_sum = in_cksum(m, (ip->ip_hl << 2));
+	ip->ip_sum = in_cksum(m, hlen);
 
 #if NBPFILTER > 0
 	if (sc->sc_if.if_bpf != NULL)
Index: sbin/ifconfig/tunnel.c
============================================================
=======
RCS file: /cvsroot/src/sbin/ifconfig/tunnel.c,v
retrieving revision 1.6
diff -u -p -u -p -r1.6 tunnel.c
--- sbin/ifconfig/tunnel.c	16 Jun 2006 23:48:35 -0000	1.6
+++ sbin/ifconfig/tunnel.c	26 Aug 2006 07:11:14 -0000
 -50,6
+50,7  __RCSID("$NetBSD: tunnel.c,v 1.6 2006/06
 #include <string.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <util.h>
 
 #include "extern.h"
 #include "tunnel.h"
 -59,9
+60,10  __RCSID("$NetBSD: tunnel.c,v 1.6 2006/06
 #endif
 
 void
-settunnel(const char *src, const char *dst)
+settunnel(const char *src0, const char *dst0)
 {
 	struct addrinfo hints, *srcres, *dstres;
+	char *dst, *dstport, *src, *srcport;
 	int ecode;
 	struct if_laddrreq req;
 
 -69,11
+71,21  settunnel(const char *src, const char *d
 	hints.ai_family = afp->af_af;
 	hints.ai_socktype = SOCK_DGRAM; /*dummy*/
 
-	if ((ecode = getaddrinfo(src, NULL, &hints,
&srcres)) != 0)
+	if ((src = strdup(src0)) == NULL)
+		err(EXIT_FAILURE, "%s: strdup", __func__);
+	if ((dst = strdup(dst0)) == NULL)
+		err(EXIT_FAILURE, "%s: strdup", __func__);
+
+	srcport = src;
+	(void)strsep(&srcport, ",");
+	dstport = dst;
+	(void)strsep(&dstport, ",");
+
+	if ((ecode = getaddrinfo(src, srcport, &hints,
&srcres)) != 0)
 		errx(EXIT_FAILURE, "error in parsing address
string: %s",
 		    gai_strerror(ecode));
 
-	if ((ecode = getaddrinfo(dst, NULL, &hints,
&dstres)) != 0)
+	if ((ecode = getaddrinfo(dst, dstport, &hints,
&dstres)) != 0)
 		errx(EXIT_FAILURE, "error in parsing address
string: %s",
 		    gai_strerror(ecode));
 
 -123,6
+135,8  settunnel(const char *src, const char *d
 
 	freeaddrinfo(srcres);
 	freeaddrinfo(dstres);
+	free(src);
+	free(dst);
 }
 
 /*ARGSUSED*/
 -134,9
+148,19  deletetunnel(const char *ifname, int par
 		err(EXIT_FAILURE, "SIOCDIFPHYADDR");
 }
 
+#if 0
+static int
+goodport(const char *port)
+{
+	return strcmp(port, ",0") != 0 &&
strcmp(port, ",N/A") != 0;
+}
+#endif
+
 void
 tunnel_status(void)
 {
+	char dstserv[sizeof(",65535")];
+	char srcserv[sizeof(",65535")];
 	char psrcaddr[NI_MAXHOST];
 	char pdstaddr[NI_MAXHOST];
 	const int niflag = NI_NUMERICHOST;
 -155,15
+179,20  tunnel_status(void)
 		in6_fillscopeid((struct sockaddr_in6 *)&req.addr);
 #endif /* INET6 */
 	getnameinfo((struct sockaddr *)&req.addr,
req.addr.ss_len,
-	    psrcaddr, sizeof(psrcaddr), 0, 0, niflag);
+	    psrcaddr, sizeof(psrcaddr), &srcserv[1],
sizeof(srcserv) - 1,
+	    niflag);
 
 #ifdef INET6
 	if (req.dstaddr.ss_family == AF_INET6)
 		in6_fillscopeid((struct sockaddr_in6 *)&req.dstaddr);
 #endif
 	getnameinfo((struct sockaddr *)&req.dstaddr,
req.dstaddr.ss_len,
-	    pdstaddr, sizeof(pdstaddr), 0, 0, niflag);
+	    pdstaddr, sizeof(pdstaddr), &dstserv[1],
sizeof(dstserv) - 1,
+	    niflag);
+
+	srcserv[0] = (strcmp(srcserv, "0") == 0) ?
'\0' : ',';
+	dstserv[0] = (strcmp(dstserv, "0") == 0) ?
'\0' : ',';
 
-	printf("\ttunnel %s %s --> %s\n", lafp ?
lafp->af_name : "???",
-	    psrcaddr, pdstaddr);
+	printf("\ttunnel %s %s%s --> %s%s\n",
lafp ? lafp->af_name : "???",
+	    psrcaddr, srcserv, pdstaddr, dstserv);
 }
rfc: gre over udp
user name
2006-08-26 07:38:11
On Sat, Aug 26, 2006 at 02:18:04AM -0500, David Young wrote:
> I need to tunnel packets through NAT routers to a
tunnel concentrator at
> my office.  To that end, I am extending gre(4) to put
tunnel packets into
> UDP datagrams.  I have attached a patch that contains
my work in progress.
> I request your feedback.

I should have mentioned that is all Matt Thomas's fault
that I extended
gre(4) instead of duplicating a bunch of gre functionality
by writing
a ipudp interface from scratch.  With his insidious advice,
Matt helped
me conserve my copious and eeeevil free time and avoid
kernel bloat.



I will take blame for the code.

Dave

-- 
David Young             OJC Technologies
dyoungojctech.com      Urbana, IL * (217) 278-3933
rfc: gre over udp
user name
2006-08-26 11:53:06
On Sat, Aug 26, 2006 at 02:18:04AM -0500, David Young wrote:
> I need to tunnel packets through NAT routers to a
tunnel concentrator at
> my office.  To that end, I am extending gre(4) to put
tunnel packets into
> UDP datagrams.  I have attached a patch that contains
my work in progress.
> I request your feedback.

Couldn't you just use tunnel-mode IPsec and NAT-T?  Or is
the complexity
of IPsec/racoon trying to be avoided?

	Jonathan Kollasch
rfc: gre over udp
user name
2006-08-26 14:57:17
Jonathan A. Kollasch wrote:
> On Sat, Aug 26, 2006 at 02:18:04AM -0500, David Young
wrote:
>   
>> I need to tunnel packets through NAT routers to a
tunnel concentrator at
>> my office.  To that end, I am extending gre(4) to
put tunnel packets into
>> UDP datagrams.  I have attached a patch that
contains my work in progress.
>> I request your feedback.
>>     
>
> Couldn't you just use tunnel-mode IPsec and NAT-T?  Or
is the complexity
> of IPsec/racoon trying to be avoided?
>
> 	Jonathan Kollasch
>   

I think the issue (if I understood it correctly) was the
need to pass
through consumer-grade NAT devices which might not pass
non-IP packets.

+j


rfc: gre over udp
user name
2006-08-26 17:19:50
On Sat, Aug 26, 2006 at 06:53:06AM -0500, Jonathan A.
Kollasch wrote:
> On Sat, Aug 26, 2006 at 02:18:04AM -0500, David Young
wrote:
> > I need to tunnel packets through NAT routers to a
tunnel concentrator at
> > my office.  To that end, I am extending gre(4) to
put tunnel packets into
> > UDP datagrams.  I have attached a patch that
contains my work in progress.
> > I request your feedback.
> 
> Couldn't you just use tunnel-mode IPsec and NAT-T?  Or
is the complexity
> of IPsec/racoon trying to be avoided?

It's not just the complexity, although IPSec HOWTOs do make
my head spin.
I want to use existing abstractions, such as the network
interface, so
that I can re-use familiar utilities and daemons:
ifconfig(8), route(8),
netstat(8), routing daemons, etc.

I am hopeful that nothing stops userland from setting up
IPSec on a UDP
socket before delegating the socket to a GRE interface.

Dave

-- 
David Young             OJC Technologies
dyoungojctech.com      Urbana, IL * (217) 278-3933
more notes on gre
user name
2006-08-26 18:53:44
On Sat, Aug 26, 2006 at 02:18:04AM -0500, David Young wrote:
> I need to tunnel packets through NAT routers to a
tunnel concentrator at
> my office.  To that end, I am extending gre(4) to put
tunnel packets into
> UDP datagrams.  I have attached a patch that contains
my work in progress.
> I request your feedback.

This work may be a springboard for a Teredo developer, since
Teredo
uses UDP to tunnel IPv6 packets through NAT firewalls.  I do
not foresee
working on Teredo, myself.

While I was testing for regressions, I found that some bogus
pointer
arithmetic has always kept gre's Mobile IP mode from
working.  I fixed
that, but I could only test one gre(4) against another
gre(4).  There's no
telling if it interoperates with anything.  Maybe the
feature should
go away.

I noticed that gre(4) is missing both the capability to
tunnel ethernet
packets, and the capability to tunnel through v6 networks. 
The latter
should be easy to add.  The former will be more difficult. 
Maybe this
will be somebody's project on a rainy day.

Dave

-- 
David Young             OJC Technologies
dyoungojctech.com      Urbana, IL * (217) 278-3933
more notes on gre
user name
2006-08-27 00:40:36
On Aug 26, 2006, at 7:53 PM, David Young wrote:

> This work may be a springboard for a Teredo developer,
since Teredo
> uses UDP to tunnel IPv6 packets through NAT firewalls. 
I do not  
> foresee
> working on Teredo, myself.
>
> While I was testing for regressions, I found that some
bogus pointer
> arithmetic has always kept gre's Mobile IP mode from
working.  I fixed
> that, but I could only test one gre(4) against another
gre(4).   
> There's no
> telling if it interoperates with anything.  Maybe the
feature should
> go away.
>
> I noticed that gre(4) is missing both the capability to
tunnel  
> ethernet
> packets, and the capability to tunnel through v6
networks.  The latter
> should be easy to add.  The former will be more
difficult.  Maybe this
> will be somebody's project on a rainy day.

Yes, that's me.

	-- Rui Paulo


[1-7]

about | contact  Other archives ( Real Estate discussion Medical topics )