Author: eugen
Date: Tue Apr  7 16:47:35 2020
New Revision: 359698
URL: https://svnweb.freebsd.org/changeset/base/359698

Log:
  MFC r342168,357786: Allow ng_nat to be attached to a ethernet interface
  
  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).
  
  Submitted by: sobomax
  Reviewed by:  glebius
  Differential Revision:        https://reviews.freebsd.org/D18535
  Relnotes:     yes

Modified:
  stable/11/share/man/man4/ng_nat.4
  stable/11/sys/netgraph/ng_nat.c
  stable/11/sys/netgraph/ng_nat.h
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/share/man/man4/ng_nat.4
==============================================================================
--- stable/11/share/man/man4/ng_nat.4   Tue Apr  7 16:44:14 2020        
(r359697)
+++ stable/11/share/man/man4/ng_nat.4   Tue Apr  7 16:47:35 2020        
(r359698)
@@ -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: stable/11/sys/netgraph/ng_nat.c
==============================================================================
--- stable/11/sys/netgraph/ng_nat.c     Tue Apr  7 16:44:14 2020        
(r359697)
+++ stable/11/sys/netgraph/ng_nat.c     Tue Apr  7 16:47:35 2020        
(r359698)
@@ -42,6 +42,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>
 
@@ -239,6 +242,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 }
 };
 
@@ -275,6 +292,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;
 
@@ -300,6 +318,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. */
@@ -692,11 +711,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;
@@ -713,7 +755,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. */
@@ -736,12 +778,44 @@ 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),
-           ("ng_nat: ip_len != m_pkthdr.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);
+       }
 
+       if (m->m_pkthdr.len < ipofs + sizeof(struct ip))
+               goto send;              /* packet too short to hold IP */
+
+       c = (char *)mtodo(m, ipofs);
+       ip = (struct ip *)mtodo(m, ipofs);
+
+       if (ip->ip_v != IPVERSION)
+               goto send;              /* other IP version, let it pass */
+       if (m->m_pkthdr.len < ipofs + ntohs(ip->ip_len))
+               goto send;              /* packet too short (i.e. fragmented or 
broken) */
+
        /*
         * We drop packet when:
         * 1. libalias returns PKT_ALIAS_ERROR;
@@ -751,7 +825,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 &&
@@ -761,7 +836,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);
@@ -771,7 +847,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: stable/11/sys/netgraph/ng_nat.h
==============================================================================
--- stable/11/sys/netgraph/ng_nat.h     Tue Apr  7 16:44:14 2020        
(r359697)
+++ stable/11/sys/netgraph/ng_nat.h     Tue Apr  7 16:47:35 2020        
(r359698)
@@ -203,6 +203,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,
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to