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
This commit is contained in:
parent
83eb920c6f
commit
b7841ae650
@ -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
|
||||
|
@ -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 lasthook)
|
||||
#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) {
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user