aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/net/pfvar.h1
-rw-r--r--sys/netpfil/pf/pf.h6
-rw-r--r--sys/netpfil/pf/pf_ioctl.c40
-rw-r--r--sys/netpfil/pf/pf_lb.c65
4 files changed, 104 insertions, 8 deletions
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index d68932db975f..e4f31dde873a 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -309,6 +309,7 @@ struct pf_kpool {
struct pf_kpooladdr *cur;
struct pf_poolhashkey key;
struct pf_addr counter;
+ struct pf_mape_portset mape;
int tblidx;
u_int16_t proxy_port[2];
u_int8_t opts;
diff --git a/sys/netpfil/pf/pf.h b/sys/netpfil/pf/pf.h
index 45a3efe91efb..011d69a746dd 100644
--- a/sys/netpfil/pf/pf.h
+++ b/sys/netpfil/pf/pf.h
@@ -317,6 +317,12 @@ struct pf_poolhashkey {
#define key32 pfk.key32
};
+struct pf_mape_portset {
+ u_int8_t offset;
+ u_int8_t psidlen;
+ u_int16_t psid;
+};
+
struct pf_pool {
struct pf_palist list;
struct pf_pooladdr *cur;
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index 66726b754a97..5312e48c2f76 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -1646,6 +1646,36 @@ pf_addr_to_nvaddr(const struct pf_addr *paddr)
}
static int
+pf_nvmape_to_mape(const nvlist_t *nvl, struct pf_mape_portset *mape)
+{
+ int error = 0;
+
+ bzero(mape, sizeof(*mape));
+ PFNV_CHK(pf_nvuint8(nvl, "offset", &mape->offset));
+ PFNV_CHK(pf_nvuint8(nvl, "psidlen", &mape->psidlen));
+ PFNV_CHK(pf_nvuint16(nvl, "psid", &mape->psid));
+
+errout:
+ return (error);
+}
+
+static nvlist_t *
+pf_mape_to_nvmape(const struct pf_mape_portset *mape)
+{
+ nvlist_t *nvl;
+
+ nvl = nvlist_create(0);
+ if (nvl == NULL)
+ return (NULL);
+
+ nvlist_add_number(nvl, "offset", mape->offset);
+ nvlist_add_number(nvl, "psidlen", mape->psidlen);
+ nvlist_add_number(nvl, "psid", mape->psid);
+
+ return (nvl);
+}
+
+static int
pf_nvpool_to_pool(const nvlist_t *nvl, struct pf_kpool *kpool)
{
int error = 0;
@@ -1664,6 +1694,11 @@ pf_nvpool_to_pool(const nvlist_t *nvl, struct pf_kpool *kpool)
NULL));
PFNV_CHK(pf_nvuint8(nvl, "opts", &kpool->opts));
+ if (nvlist_exists_nvlist(nvl, "mape")) {
+ PFNV_CHK(pf_nvmape_to_mape(nvlist_get_nvlist(nvl, "mape"),
+ &kpool->mape));
+ }
+
errout:
return (error);
}
@@ -1688,6 +1723,11 @@ pf_pool_to_nvpool(const struct pf_kpool *pool)
pf_uint16_array_nv(nvl, "proxy_port", pool->proxy_port, 2);
nvlist_add_number(nvl, "opts", pool->opts);
+ tmp = pf_mape_to_nvmape(&pool->mape);
+ if (tmp == NULL)
+ goto error;
+ nvlist_add_nvlist(nvl, "mape", tmp);
+
return (nvl);
error:
diff --git a/sys/netpfil/pf/pf_lb.c b/sys/netpfil/pf/pf_lb.c
index 0892d13d9575..3796ab9fb80a 100644
--- a/sys/netpfil/pf/pf_lb.c
+++ b/sys/netpfil/pf/pf_lb.c
@@ -224,11 +224,6 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_krule *r,
if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn))
return (1);
- if (proto == IPPROTO_ICMP) {
- low = 1;
- high = 65535;
- }
-
bzero(&key, sizeof(key));
key.af = af;
key.proto = proto;
@@ -310,6 +305,42 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_krule *r,
return (1); /* none available */
}
+static int
+pf_get_mape_sport(sa_family_t af, u_int8_t proto, struct pf_krule *r,
+ struct pf_addr *saddr, uint16_t sport, struct pf_addr *daddr,
+ uint16_t dport, struct pf_addr *naddr, uint16_t *nport,
+ struct pf_ksrc_node **sn)
+{
+ uint16_t psmask, low, highmask;
+ uint16_t i, ahigh, cut;
+ int ashift, psidshift;
+
+ ashift = 16 - r->rpool.mape.offset;
+ psidshift = ashift - r->rpool.mape.psidlen;
+ psmask = r->rpool.mape.psid & ((1U << r->rpool.mape.psidlen) - 1);
+ psmask = psmask << psidshift;
+ highmask = (1U << psidshift) - 1;
+
+ ahigh = (1U << r->rpool.mape.offset) - 1;
+ cut = arc4random() & ahigh;
+ if (cut == 0)
+ cut = 1;
+
+ for (i = cut; i <= ahigh; i++) {
+ low = (i << ashift) | psmask;
+ if (!pf_get_sport(af, proto, r, saddr, sport, daddr, dport,
+ naddr, nport, low, low | highmask, sn))
+ return (0);
+ }
+ for (i = cut - 1; i > 0; i--) {
+ low = (i << ashift) | psmask;
+ if (!pf_get_sport(af, proto, r, saddr, sport, daddr, dport,
+ naddr, nport, low, low | highmask, sn))
+ return (0);
+ }
+ return (1);
+}
+
int
pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr,
struct pf_addr *naddr, struct pf_addr *init_addr, struct pf_ksrc_node **sn)
@@ -530,6 +561,7 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
struct pf_krule *r = NULL;
struct pf_addr *naddr;
uint16_t *nport;
+ uint16_t low, high;
PF_RULES_RASSERT();
KASSERT(*skp == NULL, ("*skp not NULL"));
@@ -577,9 +609,26 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
switch (r->action) {
case PF_NAT:
- if (pf_get_sport(pd->af, pd->proto, r, saddr, sport, daddr,
- dport, naddr, nport, r->rpool.proxy_port[0],
- r->rpool.proxy_port[1], sn)) {
+ if (pd->proto == IPPROTO_ICMP) {
+ low = 1;
+ high = 65535;
+ } else {
+ low = r->rpool.proxy_port[0];
+ high = r->rpool.proxy_port[1];
+ }
+ if (r->rpool.mape.offset > 0) {
+ if (pf_get_mape_sport(pd->af, pd->proto, r, saddr,
+ sport, daddr, dport, naddr, nport, sn)) {
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("pf: MAP-E port allocation (%u/%u/%u)"
+ " failed\n",
+ r->rpool.mape.offset,
+ r->rpool.mape.psidlen,
+ r->rpool.mape.psid));
+ goto notrans;
+ }
+ } else if (pf_get_sport(pd->af, pd->proto, r, saddr, sport,
+ daddr, dport, naddr, nport, low, high, sn)) {
DPFPRINTF(PF_DEBUG_MISC,
("pf: NAT proxy port allocation (%u-%u) failed\n",
r->rpool.proxy_port[0], r->rpool.proxy_port[1]));