Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 17 Dec 2018 16:00:35 +0000 (UTC)
From:      Maxim Sobolev <sobomax@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r342168 - in head: share/man/man4 sys/netgraph
Message-ID:  <201812171600.wBHG0Zet046365@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: sobomax
Date: Mon Dec 17 16:00:35 2018
New Revision: 342168
URL: https://svnweb.freebsd.org/changeset/base/342168

Log:
  Allow ng_nat to be attached to a ethernet interface directly via ng_ether(4)
  or the likes. Add new control message types: setdlt and getdlt to switch
  from default DLT_RAW (no encapsulation) to DLT_EN10MB (ethernet).
  
  Approved by:	glebius
  MFC after:	1 month
  Differential Revision:	https://reviews.freebsd.org/D18535

Modified:
  head/share/man/man4/ng_nat.4
  head/sys/netgraph/ng_nat.c
  head/sys/netgraph/ng_nat.h

Modified: head/share/man/man4/ng_nat.4
==============================================================================
--- head/share/man/man4/ng_nat.4	Mon Dec 17 15:19:48 2018	(r342167)
+++ head/share/man/man4/ng_nat.4	Mon Dec 17 16:00:35 2018	(r342168)
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd March 21, 2013
+.Dd December 12, 2018
 .Dt NG_NAT 4
 .Os
 .Sh NAME
@@ -264,6 +264,38 @@ from its
 .Xr libalias
 instance, the corresponding field is returned as
 .Va UINT32_MAX .
+.It Dv NGM_NAT_SET_DLT Pq Ic setdlt
+Sets the data link type on the
+.Va in
+and
+.Va out
+hooks.
+Currently, supported types are
+.Cm DLT_RAW
+(raw IP datagrams , no offset applied, the default) and
+.Cm DLT_EN10MB
+(Ethernet). DLT_ definitions can be found in
+.In net/bpf.h .
+If you want to work on the
+.Xr ipfw 8
+level you must use no additional offset by specifying
+.Cm DLT_RAW .
+If, however, you attach
+.Nm
+to a network interface directly and
+.Cm EN10MB
+is specified, then the extra offset will be applied to take into account
+link-level header.
+In this mode the
+.Nm
+would also inspect appropriate type field in the Ethernet header and
+pass-through any datagrams that are not IP packets.
+.It Dv NGM_NAT_GET_DLT Pq Ic getdlt
+This control message returns the current data link type of the
+.Va in
+and
+.Va out
+hooks.
 .El
 .Pp
 In all redirection messages
@@ -336,11 +368,31 @@ serial line with HDLC encapsulation.
 SEQ
 ifconfig ng0 x.y.8.35 x.y.8.1
 .Ed
+.Pp
+The
+.Nm
+node can also be attached directly to the physical interface
+via
+.Xr ng_ether 4
+node in the graph.
+In the following example, we perform masquerading on a
+Ethernet interface connected to a public network.
+.Bd -literal -offset indent
+ifconfig igb0 inet x.y.8.35 netmask 0xfffff000
+route add default x.y.0.1
+/usr/sbin/ngctl -f- <<-SEQ
+        mkpeer igb0: nat lower in
+        name igb0:lower igb0_NAT
+        connect igb0: igb0_NAT: upper out
+        msg igb0_NAT: setdlt 1
+        msg igb0_NAT: setaliasaddr x.y.8.35
+SEQ
 .Sh SEE ALSO
 .Xr libalias 3 ,
 .Xr ng_ipfw 4 ,
 .Xr natd 8 ,
-.Xr ngctl 8
+.Xr ngctl 8 ,
+.Xr ng_ether 8
 .Sh HISTORY
 The
 .Nm

Modified: head/sys/netgraph/ng_nat.c
==============================================================================
--- head/sys/netgraph/ng_nat.c	Mon Dec 17 15:19:48 2018	(r342167)
+++ head/sys/netgraph/ng_nat.c	Mon Dec 17 16:00:35 2018	(r342168)
@@ -44,6 +44,9 @@
 #include <netinet/tcp.h>
 #include <machine/in_cksum.h>
 
+#include <net/dlt.h>
+#include <net/ethernet.h>
+
 #include <netinet/libalias/alias.h>
 #include <netinet/libalias/alias_local.h>
 
@@ -241,6 +244,20 @@ static const struct ng_cmdlist ng_nat_cmdlist[] = {
 	  NULL,
 	  &ng_nat_libalias_info_type
 	},
+	{
+	  NGM_NAT_COOKIE,
+	  NGM_NAT_SET_DLT,
+	  "setdlt",
+	  &ng_parse_uint8_type,
+	  NULL
+	},
+	{
+	  NGM_NAT_COOKIE,
+	  NGM_NAT_GET_DLT,
+	  "getdlt",
+	  NULL,
+	  &ng_parse_uint8_type
+	},
 	{ 0 }
 };
 
@@ -277,6 +294,7 @@ struct ng_nat_priv {
 	uint32_t	rdrcount;	/* number or redirects in list */
 	uint32_t	nextid;		/* for next in turn in list */
 	struct rdrhead	redirhead;	/* redirect list header */
+	uint8_t		dlt;		/* DLT_XXX from bpf.h */
 };
 typedef struct ng_nat_priv *priv_p;
 
@@ -302,6 +320,7 @@ ng_nat_constructor(node_p node)
 	/* Init redirects housekeeping. */
 	priv->rdrcount = 0;
 	priv->nextid = 1;
+	priv->dlt = DLT_RAW;
 	STAILQ_INIT(&priv->redirhead);
 
 	/* Link structs together. */
@@ -694,11 +713,34 @@ ng_nat_rcvmsg(node_p node, item_p item, hook_p lasthoo
 #undef COPY
 		    }
 			break;
+		case NGM_NAT_SET_DLT:
+			if (msg->header.arglen != sizeof(uint8_t)) {
+				error = EINVAL;
+				break;
+			}
+			switch (*(uint8_t *) msg->data) {
+			case DLT_EN10MB:
+			case DLT_RAW:
+				priv->dlt = *(uint8_t *) msg->data;
+				break;
+			default:
+				error = EINVAL;
+				break;
+			}
+			break;
 		default:
 			error = EINVAL;		/* unknown command */
 			break;
 		}
 		break;
+		case NGM_NAT_GET_DLT:
+			NG_MKRESPONSE(resp, msg, sizeof(uint8_t), M_WAITOK);
+                        if (resp == NULL) {
+                                error = ENOMEM;
+				break;
+			}
+			*((uint8_t *) resp->data) = priv->dlt;
+			break;
 	default:
 		error = EINVAL;			/* unknown cookie type */
 		break;
@@ -715,7 +757,7 @@ ng_nat_rcvdata(hook_p hook, item_p item )
 	const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
 	struct mbuf	*m;
 	struct ip	*ip;
-	int rval, error = 0;
+	int rval, ipofs, error = 0;
 	char *c;
 
 	/* We have no required hooks. */
@@ -738,10 +780,37 @@ ng_nat_rcvdata(hook_p hook, item_p item )
 
 	NGI_M(item) = m;
 
-	c = mtod(m, char *);
-	ip = mtod(m, struct ip *);
+	switch (priv->dlt) {
+	case DLT_RAW:
+		ipofs = 0;
+		break;
+	case DLT_EN10MB:
+	    {
+		struct ether_header *eh;
 
-	KASSERT(m->m_pkthdr.len == ntohs(ip->ip_len),
+		if (m->m_pkthdr.len < sizeof(struct ether_header)) {
+			NG_FREE_ITEM(item);
+			return (ENXIO);
+		}
+		eh = mtod(m, struct ether_header *);
+		switch (ntohs(eh->ether_type)) {
+		case ETHERTYPE_IP:
+		case ETHERTYPE_IPV6:
+			ipofs = sizeof(struct ether_header);
+			break;
+		default:
+			goto send;
+		}
+		break;
+	    }
+	default:
+		panic("Corrupted priv->dlt: %u", priv->dlt);
+	}
+
+	c = (char *)mtodo(m, ipofs);
+	ip = (struct ip *)mtodo(m, ipofs);
+
+	KASSERT(m->m_pkthdr.len == ipofs + ntohs(ip->ip_len),
 	    ("ng_nat: ip_len != m_pkthdr.len"));
 
 	/*
@@ -753,7 +822,8 @@ ng_nat_rcvdata(hook_p hook, item_p item )
 	 *		PKT_ALIAS_DENY_INCOMING flag is set.
 	 */
 	if (hook == priv->in) {
-		rval = LibAliasIn(priv->lib, c, m->m_len + M_TRAILINGSPACE(m));
+		rval = LibAliasIn(priv->lib, c, m->m_len - ipofs +
+		    M_TRAILINGSPACE(m));
 		if (rval == PKT_ALIAS_ERROR ||
 		    rval == PKT_ALIAS_UNRESOLVED_FRAGMENT ||
 		    (rval == PKT_ALIAS_IGNORED &&
@@ -763,7 +833,8 @@ ng_nat_rcvdata(hook_p hook, item_p item )
 			return (EINVAL);
 		}
 	} else if (hook == priv->out) {
-		rval = LibAliasOut(priv->lib, c, m->m_len + M_TRAILINGSPACE(m));
+		rval = LibAliasOut(priv->lib, c, m->m_len - ipofs +
+		    M_TRAILINGSPACE(m));
 		if (rval == PKT_ALIAS_ERROR) {
 			NG_FREE_ITEM(item);
 			return (EINVAL);
@@ -773,7 +844,7 @@ ng_nat_rcvdata(hook_p hook, item_p item )
 
 	if (rval == PKT_ALIAS_RESPOND)
 		m->m_flags |= M_SKIP_FIREWALL;
-	m->m_pkthdr.len = m->m_len = ntohs(ip->ip_len);
+	m->m_pkthdr.len = m->m_len = ntohs(ip->ip_len) + ipofs;
 
 	if ((ip->ip_off & htons(IP_OFFMASK)) == 0 &&
 	    ip->ip_p == IPPROTO_TCP) {

Modified: head/sys/netgraph/ng_nat.h
==============================================================================
--- head/sys/netgraph/ng_nat.h	Mon Dec 17 15:19:48 2018	(r342167)
+++ head/sys/netgraph/ng_nat.h	Mon Dec 17 16:00:35 2018	(r342168)
@@ -205,6 +205,8 @@ enum {
 	NGM_NAT_SET_IPADDR = 1,
 	NGM_NAT_SET_MODE,
 	NGM_NAT_SET_TARGET,
+	NGM_NAT_SET_DLT,
+	NGM_NAT_GET_DLT,
 	NGM_NAT_REDIRECT_PORT,
 	NGM_NAT_REDIRECT_ADDR,
 	NGM_NAT_REDIRECT_PROTO,



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