Index: head/share/man/man4/ng_nat.4 =================================================================== --- head/share/man/man4/ng_nat.4 +++ head/share/man/man4/ng_nat.4 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd March 21, 2013 +.Dd December 12, 2018 .Dt NG_NAT 4 .Os .Sh NAME @@ -264,6 +264,38 @@ .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 @@ 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 Index: head/sys/netgraph/ng_nat.h =================================================================== --- head/sys/netgraph/ng_nat.h +++ head/sys/netgraph/ng_nat.h @@ -205,6 +205,8 @@ 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, Index: head/sys/netgraph/ng_nat.c =================================================================== --- head/sys/netgraph/ng_nat.c +++ head/sys/netgraph/ng_nat.c @@ -44,6 +44,9 @@ #include #include +#include +#include + #include #include @@ -241,6 +244,20 @@ 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 @@ 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 @@ /* Init redirects housekeeping. */ priv->rdrcount = 0; priv->nextid = 1; + priv->dlt = DLT_RAW; STAILQ_INIT(&priv->redirhead); /* Link structs together. */ @@ -694,11 +713,34 @@ #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 @@ 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 @@ 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 @@ * 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 @@ 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 @@ 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) {