Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F132098516
D29468.id86536.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
D29468.id86536.diff
View Options
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -306,6 +306,7 @@
int type;
int staticport;
struct pf_poolhashkey *key;
+ struct pf_mape_portset mape;
} pool_opts;
@@ -461,7 +462,7 @@
%token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY FAILPOLICY
%token RANDOMID REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID
%token ANTISPOOF FOR INCLUDE
-%token BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY
+%token BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY MAPEPORTSET
%token ALTQ CBQ CODEL PRIQ HFSC FAIRQ BANDWIDTH TBRSIZE LINKSHARE REALTIME
%token UPPERLIMIT QUEUE PRIORITY QLIMIT HOGS BUCKETS RTABLE TARGET INTERVAL
%token LOAD RULESET_OPTIMIZATION PRIO
@@ -4015,6 +4016,36 @@
pool_opts.marker |= POM_STICKYADDRESS;
pool_opts.opts |= PF_POOL_STICKYADDR;
}
+ | MAPEPORTSET number '/' number '/' number {
+ if (pool_opts.mape.offset) {
+ yyerror("map-e-portset cannot be redefined");
+ YYERROR;
+ }
+ if (pool_opts.type) {
+ yyerror("map-e-portset cannot be used with "
+ "address pools");
+ YYERROR;
+ }
+ if ($2 <= 0 || $2 >= 16) {
+ yyerror("MAP-E PSID offset must be 1-15");
+ YYERROR;
+ }
+ if ($4 < 0 || $4 >= 16 || $2 + $4 > 16) {
+ yyerror("Invalid MAP-E PSID length");
+ YYERROR;
+ } else if ($4 == 0) {
+ yyerror("PSID Length = 0: this means"
+ " you do not need MAP-E");
+ YYERROR;
+ }
+ if ($6 < 0 || $6 > 65535) {
+ yyerror("Invalid MAP-E PSID");
+ YYERROR;
+ }
+ pool_opts.mape.offset = $2;
+ pool_opts.mape.psidlen = $4;
+ pool_opts.mape.psid = $6;
+ }
;
redirection : /* empty */ { $$ = NULL; }
@@ -4220,6 +4251,29 @@
r.rpool.proxy_port[1] = 0;
}
+ if ($10.mape.offset) {
+ if (r.action != PF_NAT) {
+ yyerror("the 'map-e-portset' option is"
+ " only valid with nat rules");
+ YYERROR;
+ }
+ if ($10.staticport) {
+ yyerror("the 'map-e-portset' option"
+ " can't be used 'static-port'");
+ YYERROR;
+ }
+ if (r.rpool.proxy_port[0] !=
+ PF_NAT_PROXY_PORT_LOW &&
+ r.rpool.proxy_port[1] !=
+ PF_NAT_PROXY_PORT_HIGH) {
+ yyerror("the 'map-e-portset' option"
+ " can't be used when specifying"
+ " a port range");
+ YYERROR;
+ }
+ r.rpool.mape = $10.mape;
+ }
+
expand_rule(&r, $2, $9 == NULL ? NULL : $9->host, $4,
$5.src_os, $5.src.host, $5.src.port, $5.dst.host,
$5.dst.port, 0, 0, 0, "");
@@ -5545,6 +5599,7 @@
{ "load", LOAD},
{ "log", LOG},
{ "loginterface", LOGINTERFACE},
+ { "map-e-portset", MAPEPORTSET},
{ "max", MAXIMUM},
{ "max-mss", MAXMSS},
{ "max-src-conn", MAXSRCCONN},
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
--- a/sbin/pfctl/pfctl_parser.c
+++ b/sbin/pfctl/pfctl_parser.c
@@ -486,6 +486,9 @@
printf(" sticky-address");
if (id == PF_NAT && p1 == 0 && p2 == 0)
printf(" static-port");
+ if (pool->mape.offset > 0)
+ printf(" map-e-portset %u/%u/%u",
+ pool->mape.offset, pool->mape.psidlen, pool->mape.psid);
}
const char * const pf_reasons[PFRES_MAX+1] = PFRES_NAMES;
diff --git a/share/man/man5/pf.conf.5 b/share/man/man5/pf.conf.5
--- a/share/man/man5/pf.conf.5
+++ b/share/man/man5/pf.conf.5
@@ -1998,6 +1998,26 @@
option prevents
.Xr pf 4
from modifying the source port on TCP and UDP packets.
+.It Xo Ar map-e-portset Aq Ar psid-offset
+.No / Aq Ar psid-len
+.No / Aq Ar psid
+.Xc
+With
+.Ar nat
+rules, the
+.Ar map-e-portset
+option enables the MAP-E (RFC 7597) source port translation.
+Setting up tunneling interface and pass rules for encapsulated packets
+are required in addition to the MAP-E nat rule.
+.Pp
+For example:
+.Bd -literal -offset indent
+nat on $gif_mape_if from $int_if:network to any \e
+ -> $ipv4_mape_src map-e-portset 6/8/0x34
+.Ed
+.Pp
+sets PSID offset 6, PSID length 8, PSID 0x34.
+.Ed
.El
.Pp
Additionally, the
@@ -2893,7 +2913,8 @@
[ "on" ifspec ] [ af ]
[ protospec ] hosts [ "tag" string ] [ "tagged" string ]
[ "-\*(Gt" ( redirhost | "{" redirhost-list "}" )
- [ portspec ] [ pooltype ] [ "static-port" ] ]
+ [ portspec ] [ pooltype ] [ "static-port" ]
+ [ "map-e-portset" number "/" number "/" number ] ]
binat-rule = [ "no" ] "binat" [ "pass" [ "log" [ "(" logopts ")" ] ] ]
[ "on" interface-name ] [ af ]
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -308,6 +308,7 @@
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
--- a/sys/netpfil/pf/pf.h
+++ b/sys/netpfil/pf/pf.h
@@ -311,11 +311,18 @@
#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;
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_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -1477,6 +1477,7 @@
pool->proxy_port[0] = kpool->proxy_port[0];
pool->proxy_port[1] = kpool->proxy_port[1];
pool->opts = kpool->opts;
+ pool->mape = kpool->mape;
}
static int
@@ -1494,6 +1495,7 @@
kpool->proxy_port[0] = pool->proxy_port[0];
kpool->proxy_port[1] = pool->proxy_port[1];
kpool->opts = pool->opts;
+ kpool->mape = pool->mape;
return (0);
}
diff --git a/sys/netpfil/pf/pf_lb.c b/sys/netpfil/pf/pf_lb.c
--- a/sys/netpfil/pf/pf_lb.c
+++ b/sys/netpfil/pf/pf_lb.c
@@ -224,11 +224,6 @@
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 @@
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 @@
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 @@
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]));
diff --git a/tests/sys/netpfil/pf/Makefile b/tests/sys/netpfil/pf/Makefile
--- a/tests/sys/netpfil/pf/Makefile
+++ b/tests/sys/netpfil/pf/Makefile
@@ -12,6 +12,7 @@
forward \
fragmentation \
icmp \
+ map_e \
names \
nat \
pass_block \
diff --git a/tests/sys/netpfil/pf/map_e.sh b/tests/sys/netpfil/pf/map_e.sh
new file mode 100644
--- /dev/null
+++ b/tests/sys/netpfil/pf/map_e.sh
@@ -0,0 +1,100 @@
+# $FreeBSD$
+#
+# SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+#
+# Copyright (c) 2018 Kristof Provost <kp@FreeBSD.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+. $(atf_get_srcdir)/utils.subr
+
+atf_test_case "map_e" "cleanup"
+map_e_head()
+{
+ atf_set descr 'map-e-portset test'
+ atf_set require.user root
+}
+
+map_e_body()
+{
+ NC_TRY_COUNT=12
+
+ pft_init
+
+ epair_map_e=$(vnet_mkepair)
+ epair_echo=$(vnet_mkepair)
+
+ vnet_mkjail map_e ${epair_map_e}b ${epair_echo}a
+ vnet_mkjail echo ${epair_echo}b
+
+ ifconfig ${epair_map_e}a 192.0.2.2/24 up
+ route add -net 198.51.100.0/24 192.0.2.1
+
+ jexec map_e ifconfig ${epair_map_e}b 192.0.2.1/24 up
+ jexec map_e ifconfig ${epair_echo}a 198.51.100.1/24 up
+ jexec map_e sysctl net.inet.ip.forwarding=1
+
+ jexec echo ifconfig ${epair_echo}b 198.51.100.2/24 up
+ jexec echo /usr/sbin/inetd $(atf_get_srcdir)/echo_inetd.conf
+
+ # Enable pf!
+ jexec map_e pfctl -e
+ pft_set_rules map_e \
+ "nat pass on ${epair_echo}a inet from 192.0.2.0/24 to any -> (${epair_echo}a) map-e-portset 2/12/0x342"
+
+ # Only allow specified ports.
+ jexec echo pfctl -e
+ pft_set_rules echo "block return all" \
+ "pass in on ${epair_echo}b inet proto tcp from 198.51.100.1 port 19720:19723 to (${epair_echo}b) port 7" \
+ "pass in on ${epair_echo}b inet proto tcp from 198.51.100.1 port 36104:36107 to (${epair_echo}b) port 7" \
+ "pass in on ${epair_echo}b inet proto tcp from 198.51.100.1 port 52488:52491 to (${epair_echo}b) port 7"
+
+ i=0
+ while [ ${i} -lt ${NC_TRY_COUNT} ]
+ do
+ echo "foo ${i}" | timeout 2 nc -N 198.51.100.2 7
+ if [ $? -ne 0 ]; then
+ atf_fail "nc failed (${i})"
+ fi
+ i=$((${i}+1))
+ done
+
+ sleep 1
+
+ # If the kernel is stuck in pf_get_sport() this will not succeed either.
+ timeout 2 jexec map_e pfctl -sa
+ if [ $? -eq 124 ]; then
+ # Timed out
+ atf_fail "pfctl timeout"
+ fi
+ jexec echo pfctl -sa
+}
+
+map_e_cleanup()
+{
+ pft_cleanup
+}
+
+atf_init_test_cases()
+{
+ atf_add_test_case "map_e"
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Oct 14, 4:26 PM (1 h, 30 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
23727079
Default Alt Text
D29468.id86536.diff (11 KB)
Attached To
Mode
D29468: pf: Implement the NAT source port selection of MAP-E Customer Edge
Attached
Detach File
Event Timeline
Log In to Comment