Changeset View
Changeset View
Standalone View
Standalone View
head/sys/netgraph/ng_nat.c
Show All 38 Lines | |||||
#include <netinet/in_systm.h> | #include <netinet/in_systm.h> | ||||
#include <netinet/in.h> | #include <netinet/in.h> | ||||
#include <netinet/ip.h> | #include <netinet/ip.h> | ||||
#include <netinet/ip_var.h> | #include <netinet/ip_var.h> | ||||
#include <netinet/tcp.h> | #include <netinet/tcp.h> | ||||
#include <machine/in_cksum.h> | #include <machine/in_cksum.h> | ||||
#include <net/dlt.h> | |||||
#include <net/ethernet.h> | |||||
#include <netinet/libalias/alias.h> | #include <netinet/libalias/alias.h> | ||||
#include <netinet/libalias/alias_local.h> | #include <netinet/libalias/alias_local.h> | ||||
#include <netgraph/ng_message.h> | #include <netgraph/ng_message.h> | ||||
#include <netgraph/ng_parse.h> | #include <netgraph/ng_parse.h> | ||||
#include <netgraph/ng_nat.h> | #include <netgraph/ng_nat.h> | ||||
#include <netgraph/netgraph.h> | #include <netgraph/netgraph.h> | ||||
▲ Show 20 Lines • Show All 181 Lines • ▼ Show 20 Lines | static const struct ng_cmdlist ng_nat_cmdlist[] = { | ||||
}, | }, | ||||
{ | { | ||||
NGM_NAT_COOKIE, | NGM_NAT_COOKIE, | ||||
NGM_NAT_LIBALIAS_INFO, | NGM_NAT_LIBALIAS_INFO, | ||||
"libaliasinfo", | "libaliasinfo", | ||||
NULL, | NULL, | ||||
&ng_nat_libalias_info_type | &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 } | { 0 } | ||||
}; | }; | ||||
/* Netgraph node type descriptor. */ | /* Netgraph node type descriptor. */ | ||||
static struct ng_type typestruct = { | static struct ng_type typestruct = { | ||||
.version = NG_ABI_VERSION, | .version = NG_ABI_VERSION, | ||||
.name = NG_NAT_NODE_TYPE, | .name = NG_NAT_NODE_TYPE, | ||||
.constructor = ng_nat_constructor, | .constructor = ng_nat_constructor, | ||||
Show All 20 Lines | struct ng_nat_priv { | ||||
node_p node; /* back pointer to node */ | node_p node; /* back pointer to node */ | ||||
hook_p in; /* hook for demasquerading */ | hook_p in; /* hook for demasquerading */ | ||||
hook_p out; /* hook for masquerading */ | hook_p out; /* hook for masquerading */ | ||||
struct libalias *lib; /* libalias handler */ | struct libalias *lib; /* libalias handler */ | ||||
uint32_t flags; /* status flags */ | uint32_t flags; /* status flags */ | ||||
uint32_t rdrcount; /* number or redirects in list */ | uint32_t rdrcount; /* number or redirects in list */ | ||||
uint32_t nextid; /* for next in turn in list */ | uint32_t nextid; /* for next in turn in list */ | ||||
struct rdrhead redirhead; /* redirect list header */ | struct rdrhead redirhead; /* redirect list header */ | ||||
uint8_t dlt; /* DLT_XXX from bpf.h */ | |||||
}; | }; | ||||
typedef struct ng_nat_priv *priv_p; | typedef struct ng_nat_priv *priv_p; | ||||
/* Values of flags */ | /* Values of flags */ | ||||
#define NGNAT_CONNECTED 0x1 /* We have both hooks connected */ | #define NGNAT_CONNECTED 0x1 /* We have both hooks connected */ | ||||
#define NGNAT_ADDR_DEFINED 0x2 /* NGM_NAT_SET_IPADDR happened */ | #define NGNAT_ADDR_DEFINED 0x2 /* NGM_NAT_SET_IPADDR happened */ | ||||
static int | static int | ||||
Show All 9 Lines | ng_nat_constructor(node_p node) | ||||
/* Set same ports on. */ | /* Set same ports on. */ | ||||
(void )LibAliasSetMode(priv->lib, PKT_ALIAS_SAME_PORTS, | (void )LibAliasSetMode(priv->lib, PKT_ALIAS_SAME_PORTS, | ||||
PKT_ALIAS_SAME_PORTS); | PKT_ALIAS_SAME_PORTS); | ||||
/* Init redirects housekeeping. */ | /* Init redirects housekeeping. */ | ||||
priv->rdrcount = 0; | priv->rdrcount = 0; | ||||
priv->nextid = 1; | priv->nextid = 1; | ||||
priv->dlt = DLT_RAW; | |||||
STAILQ_INIT(&priv->redirhead); | STAILQ_INIT(&priv->redirhead); | ||||
/* Link structs together. */ | /* Link structs together. */ | ||||
NG_NODE_SET_PRIVATE(node, priv); | NG_NODE_SET_PRIVATE(node, priv); | ||||
priv->node = node; | priv->node = node; | ||||
/* | /* | ||||
* libalias is not thread safe, so our node | * libalias is not thread safe, so our node | ||||
▲ Show 20 Lines • Show All 376 Lines • ▼ Show 20 Lines | i->F = UINT32_MAX; \ | ||||
COPY(sctpLinkCount); | COPY(sctpLinkCount); | ||||
COPY(protoLinkCount); | COPY(protoLinkCount); | ||||
COPY(fragmentIdLinkCount); | COPY(fragmentIdLinkCount); | ||||
COPY(fragmentPtrLinkCount); | COPY(fragmentPtrLinkCount); | ||||
COPY(sockCount); | COPY(sockCount); | ||||
#undef COPY | #undef COPY | ||||
} | } | ||||
break; | 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: | default: | ||||
error = EINVAL; | |||||
break; | |||||
} | |||||
break; | |||||
default: | |||||
error = EINVAL; /* unknown command */ | error = EINVAL; /* unknown command */ | ||||
break; | break; | ||||
} | } | ||||
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: | default: | ||||
error = EINVAL; /* unknown cookie type */ | error = EINVAL; /* unknown cookie type */ | ||||
break; | break; | ||||
} | } | ||||
NG_RESPOND_MSG(error, node, item, resp); | NG_RESPOND_MSG(error, node, item, resp); | ||||
NG_FREE_MSG(msg); | NG_FREE_MSG(msg); | ||||
return (error); | return (error); | ||||
} | } | ||||
static int | static int | ||||
ng_nat_rcvdata(hook_p hook, item_p item ) | ng_nat_rcvdata(hook_p hook, item_p item ) | ||||
{ | { | ||||
const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); | const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); | ||||
struct mbuf *m; | struct mbuf *m; | ||||
struct ip *ip; | struct ip *ip; | ||||
int rval, error = 0; | int rval, ipofs, error = 0; | ||||
char *c; | char *c; | ||||
/* We have no required hooks. */ | /* We have no required hooks. */ | ||||
if (!(priv->flags & NGNAT_CONNECTED)) { | if (!(priv->flags & NGNAT_CONNECTED)) { | ||||
NG_FREE_ITEM(item); | NG_FREE_ITEM(item); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
/* We have no alias address yet to do anything. */ | /* We have no alias address yet to do anything. */ | ||||
if (!(priv->flags & NGNAT_ADDR_DEFINED)) | if (!(priv->flags & NGNAT_ADDR_DEFINED)) | ||||
goto send; | goto send; | ||||
m = NGI_M(item); | m = NGI_M(item); | ||||
if ((m = m_megapullup(m, m->m_pkthdr.len)) == NULL) { | if ((m = m_megapullup(m, m->m_pkthdr.len)) == NULL) { | ||||
NGI_M(item) = NULL; /* avoid double free */ | NGI_M(item) = NULL; /* avoid double free */ | ||||
NG_FREE_ITEM(item); | NG_FREE_ITEM(item); | ||||
return (ENOBUFS); | return (ENOBUFS); | ||||
} | } | ||||
NGI_M(item) = m; | NGI_M(item) = m; | ||||
c = mtod(m, char *); | switch (priv->dlt) { | ||||
ip = mtod(m, struct ip *); | 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")); | ("ng_nat: ip_len != m_pkthdr.len")); | ||||
/* | /* | ||||
* We drop packet when: | * We drop packet when: | ||||
* 1. libalias returns PKT_ALIAS_ERROR; | * 1. libalias returns PKT_ALIAS_ERROR; | ||||
* 2. For incoming packets: | * 2. For incoming packets: | ||||
* a) for unresolved fragments; | * a) for unresolved fragments; | ||||
* b) libalias returns PKT_ALIAS_IGNORED and | * b) libalias returns PKT_ALIAS_IGNORED and | ||||
* PKT_ALIAS_DENY_INCOMING flag is set. | * PKT_ALIAS_DENY_INCOMING flag is set. | ||||
*/ | */ | ||||
if (hook == priv->in) { | 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 || | if (rval == PKT_ALIAS_ERROR || | ||||
rval == PKT_ALIAS_UNRESOLVED_FRAGMENT || | rval == PKT_ALIAS_UNRESOLVED_FRAGMENT || | ||||
(rval == PKT_ALIAS_IGNORED && | (rval == PKT_ALIAS_IGNORED && | ||||
(priv->lib->packetAliasMode & | (priv->lib->packetAliasMode & | ||||
PKT_ALIAS_DENY_INCOMING) != 0)) { | PKT_ALIAS_DENY_INCOMING) != 0)) { | ||||
NG_FREE_ITEM(item); | NG_FREE_ITEM(item); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
} else if (hook == priv->out) { | } 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) { | if (rval == PKT_ALIAS_ERROR) { | ||||
NG_FREE_ITEM(item); | NG_FREE_ITEM(item); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
} else | } else | ||||
panic("ng_nat: unknown hook!\n"); | panic("ng_nat: unknown hook!\n"); | ||||
if (rval == PKT_ALIAS_RESPOND) | if (rval == PKT_ALIAS_RESPOND) | ||||
m->m_flags |= M_SKIP_FIREWALL; | 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 && | if ((ip->ip_off & htons(IP_OFFMASK)) == 0 && | ||||
ip->ip_p == IPPROTO_TCP) { | ip->ip_p == IPPROTO_TCP) { | ||||
struct tcphdr *th = (struct tcphdr *)((caddr_t)ip + | struct tcphdr *th = (struct tcphdr *)((caddr_t)ip + | ||||
(ip->ip_hl << 2)); | (ip->ip_hl << 2)); | ||||
/* | /* | ||||
* Here is our terrible HACK. | * Here is our terrible HACK. | ||||
▲ Show 20 Lines • Show All 107 Lines • Show Last 20 Lines |