Page MenuHomeFreeBSD

D49221.diff
No OneTemporary

D49221.diff

diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -525,7 +525,7 @@
%token STICKYADDRESS ENDPI MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE
%token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY PFLOW ALLOW_RELATED
%token TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS
-%token DIVERTTO DIVERTREPLY BRIDGE_TO RECEIVEDON NE LE GE AFTO
+%token DIVERTTO DIVERTREPLY BRIDGE_TO RECEIVEDON NE LE GE AFTO NATTO RDRTO
%token <v.string> STRING
%token <v.number> NUMBER
%token <v.i> PORTBINARY
@@ -962,6 +962,10 @@
}
memset(&r, 0, sizeof(r));
+ TAILQ_INIT(&(r.rdr.list));
+ TAILQ_INIT(&(r.nat.list));
+ TAILQ_INIT(&(r.route.list));
+
if (pf->astack[pf->asd + 1]) {
if ($2 && strchr($2, '/') != NULL) {
free($2);
@@ -1094,6 +1098,9 @@
}
memset(&r, 0, sizeof(r));
+ TAILQ_INIT(&(r.rdr.list));
+ TAILQ_INIT(&(r.nat.list));
+ TAILQ_INIT(&(r.route.list));
r.action = PF_NAT;
r.af = $4;
r.rtableid = $7;
@@ -1115,6 +1122,9 @@
}
memset(&r, 0, sizeof(r));
+ TAILQ_INIT(&(r.rdr.list));
+ TAILQ_INIT(&(r.nat.list));
+ TAILQ_INIT(&(r.route.list));
r.action = PF_RDR;
r.af = $4;
r.rtableid = $7;
@@ -1157,6 +1167,10 @@
}
memset(&r, 0, sizeof(r));
+ TAILQ_INIT(&(r.rdr.list));
+ TAILQ_INIT(&(r.nat.list));
+ TAILQ_INIT(&(r.route.list));
+
r.action = PF_BINAT;
r.af = $4;
r.rtableid = $7;
@@ -1422,6 +1436,9 @@
YYERROR;
memset(&r, 0, sizeof(r));
+ TAILQ_INIT(&(r.rdr.list));
+ TAILQ_INIT(&(r.nat.list));
+ TAILQ_INIT(&(r.route.list));
r.action = $1.b1;
r.direction = $2;
@@ -1584,6 +1601,9 @@
for (i = $3; i; i = i->next) {
bzero(&r, sizeof(r));
+ TAILQ_INIT(&(r.rdr.list));
+ TAILQ_INIT(&(r.nat.list));
+ TAILQ_INIT(&(r.route.list));
r.action = PF_DROP;
r.direction = PF_IN;
@@ -2369,6 +2389,9 @@
YYERROR;
memset(&r, 0, sizeof(r));
+ TAILQ_INIT(&(r.rdr.list));
+ TAILQ_INIT(&(r.nat.list));
+ TAILQ_INIT(&(r.route.list));
r.action = $1.b1;
switch ($1.b2) {
@@ -3011,6 +3034,20 @@
filter_opts.marker |= FOM_SCRUB_TCP;
filter_opts.marker |= $3.marker;
}
+ | NATTO port_redirspec {
+ if (filter_opts.nat) {
+ yyerror("cannot respecify nat-to/binat-to");
+ YYERROR;
+ }
+ filter_opts.nat = $2;
+ }
+ | RDRTO port_redirspec {
+ if (filter_opts.rdr) {
+ yyerror("cannot respecify rdr-to");
+ YYERROR;
+ }
+ filter_opts.rdr = $2;
+ }
| AFTO af FROM port_redirspec {
if (filter_opts.nat) {
yyerror("cannot respecify af-to");
@@ -4778,6 +4815,9 @@
YYERROR;
memset(&r, 0, sizeof(r));
+ TAILQ_INIT(&(r.rdr.list));
+ TAILQ_INIT(&(r.nat.list));
+ TAILQ_INIT(&(r.route.list));
r.action = $1.b1;
r.natpass = $1.b2;
@@ -4872,6 +4912,9 @@
YYERROR;
memset(&binat, 0, sizeof(binat));
+ TAILQ_INIT(&(binat.rdr.list));
+ TAILQ_INIT(&(binat.nat.list));
+ TAILQ_INIT(&(binat.route.list));
if ($1 && $3.b1) {
yyerror("\"pass\" not valid with \"no\"");
@@ -5022,8 +5065,6 @@
YYERROR;
}
- TAILQ_INIT(&binat.rdr.list);
- TAILQ_INIT(&binat.nat.list);
pa = calloc(1, sizeof(struct pf_pooladdr));
if (pa == NULL)
err(1, "binat: calloc");
@@ -5372,9 +5413,15 @@
problems++;
}
}
- if (r->rdr.opts & PF_POOL_STICKYADDR && !r->keep_state) {
- yyerror("'sticky-address' requires 'keep state'");
- problems++;
+ if (!TAILQ_EMPTY(&(r->nat.list)) || !TAILQ_EMPTY(&(r->rdr.list))) {
+ if (r->action != PF_MATCH && !r->keep_state) {
+ yyerror("nat-to and rdr-to require keep state");
+ problems++;
+ }
+ if (r->direction == PF_INOUT) {
+ yyerror("nat-to and rdr-to require a direction");
+ problems++;
+ }
}
return (-problems);
}
@@ -6118,7 +6165,6 @@
memcpy(&(rpool->key), rs->pool_opts.key,
sizeof(struct pf_poolhashkey));
- TAILQ_INIT(&(rpool->list));
for (h = rs->host; h != NULL; h = h->next) {
pa = calloc(1, sizeof(struct pf_pooladdr));
if (pa == NULL)
@@ -6292,17 +6338,20 @@
if (r->action == PF_RDR) {
error += apply_rdr_ports(r, &(r->rdr), rdr);
+ error += apply_redirspec(&(r->rdr), rdr);
} else if (r->action == PF_NAT) {
error += apply_nat_ports(&(r->rdr), rdr);
+ error += apply_redirspec(&(r->rdr), rdr);
+ } else {
+ error += apply_redirspec(&(r->route), route);
+
+ error += apply_nat_ports(&(r->nat), nat);
+ error += apply_redirspec(&(r->nat), nat);
+
+ error += apply_rdr_ports(r, &(r->rdr), rdr);
+ error += apply_redirspec(&(r->rdr), rdr);
}
- error += apply_redirspec(&(r->nat), nat);
- error += apply_redirspec(&(r->rdr), rdr);
- error += apply_redirspec(&(r->route), route);
-
- r->nat.proxy_port[0] = PF_NAT_PROXY_PORT_LOW;
- r->nat.proxy_port[1] = PF_NAT_PROXY_PORT_HIGH;
-
if (rule_consistent(r, anchor_call[0]) < 0 || error)
yyerror("skipping rule due to errors");
else {
@@ -6491,6 +6540,7 @@
{ "modulate", MODULATE},
{ "nat", NAT},
{ "nat-anchor", NATANCHOR},
+ { "nat-to", NATTO},
{ "no", NO},
{ "no-df", NODF},
{ "no-route", NOROUTE},
@@ -6515,6 +6565,7 @@
{ "random-id", RANDOMID},
{ "rdr", RDR},
{ "rdr-anchor", RDRANCHOR},
+ { "rdr-to", RDRTO},
{ "realtime", REALTIME},
{ "reassemble", REASSEMBLE},
{ "received-on", RECEIVEDON},
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
@@ -1240,25 +1240,34 @@
}
#endif
}
- if (!anchor_call[0] && ! TAILQ_EMPTY(&r->nat.list) &&
- r->rule_flag & PFRULE_AFTO) {
- printf(" af-to %s from ", r->naf == AF_INET ? "inet" : "inet6");
- print_pool(&r->nat, r->nat.proxy_port[0], r->nat.proxy_port[1],
- r->naf ? r->naf : r->af, PF_NAT);
+ if (anchor_call[0])
+ return;
+ if (r->action == PF_NAT || r->action == PF_BINAT || r->action == PF_RDR) {
+ printf(" -> ");
+ print_pool(&r->rdr, r->rdr.proxy_port[0],
+ r->rdr.proxy_port[1], r->af, r->action);
+ } else {
+ if (!TAILQ_EMPTY(&r->nat.list)) {
+ if (r->rule_flag & PFRULE_AFTO) {
+ printf(" af-to %s from ", r->naf == AF_INET ? "inet" : "inet6");
+ } else {
+ printf(" nat-to ");
+ }
+ print_pool(&r->nat, r->nat.proxy_port[0],
+ r->nat.proxy_port[1], r->naf ? r->naf : r->af,
+ PF_NAT);
+ }
if (!TAILQ_EMPTY(&r->rdr.list)) {
- printf(" to ");
+ if (r->rule_flag & PFRULE_AFTO) {
+ printf(" to ");
+ } else {
+ printf(" rdr-to ");
+ }
print_pool(&r->rdr, r->rdr.proxy_port[0],
r->rdr.proxy_port[1], r->naf ? r->naf : r->af,
PF_RDR);
}
}
- if (!anchor_call[0] &&
- (r->action == PF_NAT || r->action == PF_BINAT ||
- r->action == PF_RDR)) {
- printf(" -> ");
- print_pool(&r->rdr, r->rdr.proxy_port[0],
- r->rdr.proxy_port[1], r->af, r->action);
- }
}
void
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -2696,6 +2696,13 @@
int, struct pf_state_key **, struct pf_state_key **,
struct pf_kanchor_stackframe *, struct pf_krule **,
struct pf_udp_mapping **udp_mapping);
+u_short pf_get_transaddr(struct pf_pdesc *,
+ struct pf_state_key **, struct pf_state_key **,
+ struct pf_krule *, struct pf_udp_mapping **,
+ u_int8_t, struct pf_kpool *);
+int pf_translate_compat(struct pf_pdesc *,
+ struct pf_state_key *, struct pf_state_key *,
+ struct pf_krule *, u_int16_t);
int pf_state_key_setup(struct pf_pdesc *,
u_int16_t, u_int16_t,
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -347,7 +347,8 @@
struct pf_krule *, struct pf_pdesc *,
struct pf_state_key *, struct pf_state_key *, int *,
struct pf_kstate **, int, u_int16_t, u_int16_t,
- struct pf_krule_slist *, struct pf_udp_mapping *);
+ struct pf_krule_slist *, struct pf_udp_mapping *,
+ struct pf_kpool *);
static int pf_state_key_addr_setup(struct pf_pdesc *,
struct pf_state_key_cmp *, int);
static int pf_tcp_track_full(struct pf_kstate **,
@@ -5466,6 +5467,58 @@
} \
} while (0)
+static __inline u_short
+pf_rule_apply_nat(struct pf_pdesc *pd, struct pf_state_key **skp,
+ struct pf_state_key **nkp, struct pf_krule *r, struct pf_krule **nr,
+ struct pf_udp_mapping **udp_mapping, u_int16_t virtual_type, int *rewrite,
+ struct pf_kpool **nat_pool)
+{
+ u_short transerror;
+ u_int8_t nat_action;
+
+ if (r->rule_flag & PFRULE_AFTO) {
+ /* Don't translate if there was an old style NAT rule */
+ if (*nr != NULL)
+ return (PFRES_TRANSLATE);
+
+ /* pass af-to rules, unsupported on match rules */
+ KASSERT(r->action != PF_MATCH, ("%s: af-to on match rule", __func__));
+ /* XXX I can imagine scenarios where we have both NAT and RDR source tracking */
+ *nat_pool = &(r->nat);
+ (*nr) = r;
+ pd->naf = r->naf;
+ if (pf_get_transaddr_af(*nr, pd) == -1) {
+ return (PFRES_TRANSLATE);
+ }
+ return (PFRES_MATCH);
+ } else if (r->rdr.cur || r->nat.cur) {
+ /* Don't translate if there was an old style NAT rule */
+ if (*nr != NULL)
+ return (PFRES_TRANSLATE);
+
+ /* match/pass nat-to/rdr-to rules */
+ (*nr) = r;
+ if (r->nat.cur) {
+ nat_action = PF_NAT;
+ *nat_pool = &(r->nat);
+ } else {
+ nat_action = PF_RDR;
+ *nat_pool = &(r->rdr);
+ }
+
+ transerror = pf_get_transaddr(pd, skp, nkp, *nr, udp_mapping,
+ nat_action, *nat_pool);
+ if (transerror == PFRES_MATCH) {
+ (*rewrite) += pf_translate_compat(pd, *skp, *nkp, *nr,
+ virtual_type);
+ return(PFRES_MATCH);
+ }
+ return (transerror);
+ }
+
+ return (PFRES_MAX);
+}
+
static int
pf_test_rule(struct pf_krule **rm, struct pf_kstate **sm,
struct pf_pdesc *pd, struct pf_krule **am,
@@ -5489,6 +5542,7 @@
u_int8_t icmptype = 0, icmpcode = 0;
struct pf_kanchor_stackframe anchor_stack[PF_ANCHOR_STACKSIZE];
struct pf_udp_mapping *udp_mapping = NULL;
+ struct pf_kpool *nat_pool = NULL;
PF_RULES_RASSERT();
@@ -5504,12 +5558,17 @@
pd->lookup.done = 1;
}
+ if (pd->ip_sum)
+ bip_sum = *pd->ip_sum;
+
switch (pd->virtual_proto) {
case IPPROTO_TCP:
+ bproto_sum = th->th_sum;
pd->nsport = th->th_sport;
pd->ndport = th->th_dport;
break;
case IPPROTO_UDP:
+ bproto_sum = pd->hdr.udp.uh_sum;
pd->nsport = pd->hdr.udp.uh_sport;
pd->ndport = pd->hdr.udp.uh_dport;
break;
@@ -5573,175 +5632,13 @@
case PFRES_MATCH:
KASSERT(sk != NULL, ("%s: null sk", __func__));
KASSERT(nk != NULL, ("%s: null nk", __func__));
-
if (nr->log) {
PFLOG_PACKET(nr->action, PFRES_MATCH, nr, a,
ruleset, pd, 1, NULL);
}
- if (pd->ip_sum)
- bip_sum = *pd->ip_sum;
-
- switch (pd->proto) {
- case IPPROTO_TCP:
- bproto_sum = th->th_sum;
-
- if (PF_ANEQ(&pd->nsaddr, &nk->addr[pd->sidx], pd->af) ||
- nk->port[pd->sidx] != pd->nsport) {
- pf_change_ap(pd->m, pd->src, &th->th_sport,
- pd->ip_sum, &th->th_sum, &nk->addr[pd->sidx],
- nk->port[pd->sidx], 0, pd->af, pd->naf);
- pd->sport = &th->th_sport;
- pd->nsport = th->th_sport;
- PF_ACPY(&pd->nsaddr, pd->src, pd->af);
- }
-
- if (PF_ANEQ(&pd->ndaddr, &nk->addr[pd->didx], pd->af) ||
- nk->port[pd->didx] != pd->ndport) {
- pf_change_ap(pd->m, pd->dst, &th->th_dport,
- pd->ip_sum, &th->th_sum, &nk->addr[pd->didx],
- nk->port[pd->didx], 0, pd->af, pd->naf);
- pd->dport = &th->th_dport;
- pd->ndport = th->th_dport;
- PF_ACPY(&pd->ndaddr, pd->dst, pd->af);
- }
- rewrite++;
- break;
- case IPPROTO_UDP:
- bproto_sum = pd->hdr.udp.uh_sum;
-
- if (PF_ANEQ(&pd->nsaddr, &nk->addr[pd->sidx], pd->af) ||
- nk->port[pd->sidx] != pd->nsport) {
- pf_change_ap(pd->m, pd->src,
- &pd->hdr.udp.uh_sport,
- pd->ip_sum, &pd->hdr.udp.uh_sum,
- &nk->addr[pd->sidx],
- nk->port[pd->sidx], 1, pd->af, pd->naf);
- pd->sport = &pd->hdr.udp.uh_sport;
- pd->nsport = pd->hdr.udp.uh_sport;
- PF_ACPY(&pd->nsaddr, pd->src, pd->af);
- }
-
- if (PF_ANEQ(&pd->ndaddr, &nk->addr[pd->didx], pd->af) ||
- nk->port[pd->didx] != pd->ndport) {
- pf_change_ap(pd->m, pd->dst,
- &pd->hdr.udp.uh_dport,
- pd->ip_sum, &pd->hdr.udp.uh_sum,
- &nk->addr[pd->didx],
- nk->port[pd->didx], 1, pd->af, pd->naf);
- pd->dport = &pd->hdr.udp.uh_dport;
- pd->ndport = pd->hdr.udp.uh_dport;
- PF_ACPY(&pd->ndaddr, pd->dst, pd->af);
- }
- rewrite++;
- break;
- case IPPROTO_SCTP: {
- uint16_t checksum = 0;
-
- if (PF_ANEQ(&pd->nsaddr, &nk->addr[pd->sidx], pd->af) ||
- nk->port[pd->sidx] != pd->nsport) {
- pf_change_ap(pd->m, pd->src,
- &pd->hdr.sctp.src_port, pd->ip_sum, &checksum,
- &nk->addr[pd->sidx],
- nk->port[pd->sidx], 1, pd->af, pd->naf);
- pd->sport = &pd->hdr.sctp.src_port;
- pd->nsport = pd->hdr.sctp.src_port;
- PF_ACPY(&pd->nsaddr, pd->src, pd->af);
- }
- if (PF_ANEQ(&pd->ndaddr, &nk->addr[pd->didx], pd->af) ||
- nk->port[pd->didx] != pd->ndport) {
- pf_change_ap(pd->m, pd->dst,
- &pd->hdr.sctp.dest_port, pd->ip_sum, &checksum,
- &nk->addr[pd->didx],
- nk->port[pd->didx], 1, pd->af, pd->naf);
- pd->dport = &pd->hdr.sctp.dest_port;
- pd->ndport = pd->hdr.sctp.dest_port;
- PF_ACPY(&pd->ndaddr, pd->dst, pd->af);
- }
- break;
- }
-#ifdef INET
- case IPPROTO_ICMP:
- if (PF_ANEQ(&pd->nsaddr, &nk->addr[pd->sidx], AF_INET)) {
- pf_change_a(&pd->src->v4.s_addr, pd->ip_sum,
- nk->addr[pd->sidx].v4.s_addr, 0);
- PF_ACPY(&pd->nsaddr, pd->src, pd->af);
- }
-
- if (PF_ANEQ(&pd->ndaddr, &nk->addr[pd->didx], AF_INET)) {
- pf_change_a(&pd->dst->v4.s_addr, pd->ip_sum,
- nk->addr[pd->didx].v4.s_addr, 0);
- PF_ACPY(&pd->ndaddr, pd->dst, pd->af);
- }
-
- if (virtual_type == htons(ICMP_ECHO) &&
- nk->port[pd->sidx] != pd->hdr.icmp.icmp_id) {
- pd->hdr.icmp.icmp_cksum = pf_cksum_fixup(
- pd->hdr.icmp.icmp_cksum, pd->nsport,
- nk->port[pd->sidx], 0);
- pd->hdr.icmp.icmp_id = nk->port[pd->sidx];
- pd->sport = &pd->hdr.icmp.icmp_id;
- }
- m_copyback(pd->m, pd->off, ICMP_MINLEN, (caddr_t)&pd->hdr.icmp);
- break;
-#endif /* INET */
-#ifdef INET6
- case IPPROTO_ICMPV6:
- if (PF_ANEQ(&pd->nsaddr, &nk->addr[pd->sidx], AF_INET6)) {
- pf_change_a6(pd->src, &pd->hdr.icmp6.icmp6_cksum,
- &nk->addr[pd->sidx], 0);
- PF_ACPY(&pd->nsaddr, pd->src, pd->af);
- }
-
- if (PF_ANEQ(&pd->ndaddr, &nk->addr[pd->didx], AF_INET6)) {
- pf_change_a6(pd->dst, &pd->hdr.icmp6.icmp6_cksum,
- &nk->addr[pd->didx], 0);
- PF_ACPY(&pd->ndaddr, pd->dst, pd->af);
- }
- rewrite++;
- break;
-#endif /* INET */
- default:
- switch (pd->af) {
-#ifdef INET
- case AF_INET:
- if (PF_ANEQ(&pd->nsaddr,
- &nk->addr[pd->sidx], AF_INET)) {
- pf_change_a(&pd->src->v4.s_addr,
- pd->ip_sum,
- nk->addr[pd->sidx].v4.s_addr, 0);
- PF_ACPY(&pd->nsaddr, pd->src, pd->af);
- }
-
- if (PF_ANEQ(&pd->ndaddr,
- &nk->addr[pd->didx], AF_INET)) {
- pf_change_a(&pd->dst->v4.s_addr,
- pd->ip_sum,
- nk->addr[pd->didx].v4.s_addr, 0);
- PF_ACPY(&pd->ndaddr, pd->dst, pd->af);
- }
- break;
-#endif /* INET */
-#ifdef INET6
- case AF_INET6:
- if (PF_ANEQ(&pd->nsaddr,
- &nk->addr[pd->sidx], AF_INET6)) {
- PF_ACPY(&pd->nsaddr, &nk->addr[pd->sidx], pd->af);
- PF_ACPY(pd->src, &nk->addr[pd->sidx], pd->af);
- }
-
- if (PF_ANEQ(&pd->ndaddr,
- &nk->addr[pd->didx], AF_INET6)) {
- PF_ACPY(&pd->ndaddr, &nk->addr[pd->didx], pd->af);
- PF_ACPY(pd->dst, &nk->addr[pd->didx], pd->af);
- }
- break;
-#endif /* INET */
- }
- break;
- }
- if (nr->natpass)
- r = NULL;
+ rewrite += pf_translate_compat(pd, sk, nk, nr, virtual_type);
+ nat_pool = &(nr->rdr);
}
while (r != NULL) {
@@ -5847,6 +5744,24 @@
tag = r->tag;
if (r->anchor == NULL) {
if (r->action == PF_MATCH) {
+ /*
+ * Apply translations before increasing counters,
+ * in case it fails.
+ */
+ transerror = pf_rule_apply_nat(pd, &sk, &nk, r,
+ &nr, &udp_mapping, virtual_type, &rewrite,
+ &nat_pool);
+ switch (transerror) {
+ case PFRES_MATCH:
+ /* Translation action found in rule and applied successfully */
+ case PFRES_MAX:
+ /* No translation action found in rule */
+ break;
+ default:
+ /* Translation action found in rule but failed to apply */
+ REASON_SET(&reason, transerror);
+ goto cleanup;
+ }
ri = malloc(sizeof(struct pf_krule_item), M_PF_RULE_ITEM, M_NOWAIT | M_ZERO);
if (ri == NULL) {
REASON_SET(&reason, PFRES_MEMORY);
@@ -5859,14 +5774,6 @@
pf_counter_u64_add_protected(&r->bytes[pd->dir == PF_OUT], pd->tot_len);
pf_counter_u64_critical_exit();
pf_rule_to_actions(r, &pd->act);
- if (r->rule_flag & PFRULE_AFTO)
- pd->naf = r->naf;
- if (pd->af != pd->naf) {
- if (pf_get_transaddr_af(r, pd) == -1) {
- REASON_SET(&reason, PFRES_TRANSLATE);
- goto cleanup;
- }
- }
if (r->log)
PFLOG_PACKET(r->action, PFRES_MATCH, r,
a, ruleset, pd, 1, NULL);
@@ -5897,13 +5804,18 @@
/* apply actions for last matching pass/block rule */
pf_rule_to_actions(r, &pd->act);
- if (r->rule_flag & PFRULE_AFTO)
- pd->naf = r->naf;
- if (pd->af != pd->naf) {
- if (pf_get_transaddr_af(r, pd) == -1) {
- REASON_SET(&reason, PFRES_TRANSLATE);
- goto cleanup;
- }
+ transerror = pf_rule_apply_nat(pd, &sk, &nk, r, &nr, &udp_mapping,
+ virtual_type, &rewrite, &nat_pool);
+ switch (transerror) {
+ case PFRES_MATCH:
+ /* Translation action found in rule and applied successfully */
+ case PFRES_MAX:
+ /* No translation action found in rule */
+ break;
+ default:
+ /* Translation action found in rule but failed to apply */
+ REASON_SET(&reason, transerror);
+ goto cleanup;
}
if (r->log) {
@@ -5961,7 +5873,7 @@
action = pf_create_state(r, nr, a, pd, nk, sk,
&rewrite, sm, tag, bproto_sum, bip_sum,
- &match_rules, udp_mapping);
+ &match_rules, udp_mapping, nat_pool);
if (action != PF_PASS) {
pf_udp_mapping_release(udp_mapping);
pd->act.log |= PF_LOG_FORCE;
@@ -6048,7 +5960,7 @@
struct pf_pdesc *pd, struct pf_state_key *nk, struct pf_state_key *sk,
int *rewrite, struct pf_kstate **sm, int tag, u_int16_t bproto_sum,
u_int16_t bip_sum, struct pf_krule_slist *match_rules,
- struct pf_udp_mapping *udp_mapping)
+ struct pf_udp_mapping *udp_mapping, struct pf_kpool *nat_pool)
{
struct pf_kstate *s = NULL;
struct pf_ksrc_node *sns[PF_SN_MAX] = { NULL };
@@ -6079,20 +5991,32 @@
goto csfailed;
}
/* src node for route-to rule */
- if (TAILQ_EMPTY(&pool_route->list)) /* Backwards compatibility. */
- pool_route = &r->rdr;
- if ((pool_route->opts & PF_POOL_STICKYADDR) &&
- (sn_reason = pf_insert_src_node(sns, snhs, r, pd->src, pd->af,
- &pd->act.rt_addr, pd->act.rt_kif, PF_SN_ROUTE)) != 0) {
- REASON_SET(&reason, sn_reason);
- goto csfailed;
+
+ if (r->rt) {
+ /*
+ * Backwards compatibility.
+ * XXX: Should we move it to rule creation?
+ */
+ if (TAILQ_EMPTY(&pool_route->list))
+ pool_route = &r->rdr;
+ if ((pool_route->opts & PF_POOL_STICKYADDR) &&
+ (sn_reason = pf_insert_src_node(sns, snhs, r, pd->src,
+ pd->af, &pd->act.rt_addr, pd->act.rt_kif,
+ PF_SN_ROUTE)) != 0) {
+ REASON_SET(&reason, sn_reason);
+ goto csfailed;
+ }
}
/* src node for translation rule */
- if (nr != NULL && (nr->rdr.opts & PF_POOL_STICKYADDR) &&
- (sn_reason = pf_insert_src_node(sns, snhs, nr, &sk->addr[pd->sidx],
- pd->af, &nk->addr[1], NULL, PF_SN_NAT)) != 0 ) {
- REASON_SET(&reason, sn_reason);
- goto csfailed;
+ if (nr != NULL) {
+ KASSERT(nat_pool != NULL, ("%s: nat_pool is NULL", __func__));
+ if ((nat_pool->opts & PF_POOL_STICKYADDR) &&
+ (sn_reason = pf_insert_src_node(sns, snhs, nr,
+ &sk->addr[pd->sidx], pd->af, &nk->addr[1], NULL,
+ PF_SN_NAT)) != 0 ) {
+ REASON_SET(&reason, sn_reason);
+ goto csfailed;
+ }
}
s = pf_alloc_state(M_NOWAIT);
if (s == NULL) {
@@ -6208,9 +6132,7 @@
/*
* sk/nk could already been setup by pf_get_translation().
*/
- if (nr == NULL) {
- KASSERT((sk == NULL && nk == NULL), ("%s: nr %p sk %p, nk %p",
- __func__, nr, sk, nk));
+ if (sk == NULL && nk == NULL) {
MPASS(pd->sport == NULL || (pd->osport == *pd->sport));
MPASS(pd->dport == NULL || (pd->odport == *pd->dport));
if (pf_state_key_setup(pd, pd->nsport, pd->ndport, &sk, &nk)) {
@@ -6423,6 +6345,174 @@
return (rewrite);
}
+int
+pf_translate_compat(struct pf_pdesc *pd, struct pf_state_key *sk,
+ struct pf_state_key *nk, struct pf_krule *nr, u_int16_t virtual_type)
+{
+ struct tcphdr *th = &pd->hdr.tcp;
+ int rewrite = 0;
+
+ KASSERT(sk != NULL, ("%s: null sk", __func__));
+ KASSERT(nk != NULL, ("%s: null nk", __func__));
+
+ switch (pd->proto) {
+ case IPPROTO_TCP:
+ if (PF_ANEQ(&pd->nsaddr, &nk->addr[pd->sidx], pd->af) ||
+ nk->port[pd->sidx] != pd->nsport) {
+ pf_change_ap(pd->m, pd->src, &th->th_sport,
+ pd->ip_sum, &th->th_sum, &nk->addr[pd->sidx],
+ nk->port[pd->sidx], 0, pd->af, pd->naf);
+ pd->sport = &th->th_sport;
+ pd->nsport = th->th_sport;
+ PF_ACPY(&pd->nsaddr, pd->src, pd->af);
+ }
+
+ if (PF_ANEQ(&pd->ndaddr, &nk->addr[pd->didx], pd->af) ||
+ nk->port[pd->didx] != pd->ndport) {
+ pf_change_ap(pd->m, pd->dst, &th->th_dport,
+ pd->ip_sum, &th->th_sum, &nk->addr[pd->didx],
+ nk->port[pd->didx], 0, pd->af, pd->naf);
+ pd->dport = &th->th_dport;
+ pd->ndport = th->th_dport;
+ PF_ACPY(&pd->ndaddr, pd->dst, pd->af);
+ }
+ rewrite++;
+ break;
+ case IPPROTO_UDP:
+
+ if (PF_ANEQ(&pd->nsaddr, &nk->addr[pd->sidx], pd->af) ||
+ nk->port[pd->sidx] != pd->nsport) {
+ pf_change_ap(pd->m, pd->src,
+ &pd->hdr.udp.uh_sport,
+ pd->ip_sum, &pd->hdr.udp.uh_sum,
+ &nk->addr[pd->sidx],
+ nk->port[pd->sidx], 1, pd->af, pd->naf);
+ pd->sport = &pd->hdr.udp.uh_sport;
+ pd->nsport = pd->hdr.udp.uh_sport;
+ PF_ACPY(&pd->nsaddr, pd->src, pd->af);
+ }
+
+ if (PF_ANEQ(&pd->ndaddr, &nk->addr[pd->didx], pd->af) ||
+ nk->port[pd->didx] != pd->ndport) {
+ pf_change_ap(pd->m, pd->dst,
+ &pd->hdr.udp.uh_dport,
+ pd->ip_sum, &pd->hdr.udp.uh_sum,
+ &nk->addr[pd->didx],
+ nk->port[pd->didx], 1, pd->af, pd->naf);
+ pd->dport = &pd->hdr.udp.uh_dport;
+ pd->ndport = pd->hdr.udp.uh_dport;
+ PF_ACPY(&pd->ndaddr, pd->dst, pd->af);
+ }
+ rewrite++;
+ break;
+ case IPPROTO_SCTP: {
+ uint16_t checksum = 0;
+
+ if (PF_ANEQ(&pd->nsaddr, &nk->addr[pd->sidx], pd->af) ||
+ nk->port[pd->sidx] != pd->nsport) {
+ pf_change_ap(pd->m, pd->src,
+ &pd->hdr.sctp.src_port, pd->ip_sum, &checksum,
+ &nk->addr[pd->sidx],
+ nk->port[pd->sidx], 1, pd->af, pd->naf);
+ pd->sport = &pd->hdr.sctp.src_port;
+ pd->nsport = pd->hdr.sctp.src_port;
+ PF_ACPY(&pd->nsaddr, pd->src, pd->af);
+ }
+ if (PF_ANEQ(&pd->ndaddr, &nk->addr[pd->didx], pd->af) ||
+ nk->port[pd->didx] != pd->ndport) {
+ pf_change_ap(pd->m, pd->dst,
+ &pd->hdr.sctp.dest_port, pd->ip_sum, &checksum,
+ &nk->addr[pd->didx],
+ nk->port[pd->didx], 1, pd->af, pd->naf);
+ pd->dport = &pd->hdr.sctp.dest_port;
+ pd->ndport = pd->hdr.sctp.dest_port;
+ PF_ACPY(&pd->ndaddr, pd->dst, pd->af);
+ }
+ break;
+ }
+#ifdef INET
+ case IPPROTO_ICMP:
+ if (PF_ANEQ(&pd->nsaddr, &nk->addr[pd->sidx], AF_INET)) {
+ pf_change_a(&pd->src->v4.s_addr, pd->ip_sum,
+ nk->addr[pd->sidx].v4.s_addr, 0);
+ PF_ACPY(&pd->nsaddr, pd->src, pd->af);
+ }
+
+ if (PF_ANEQ(&pd->ndaddr, &nk->addr[pd->didx], AF_INET)) {
+ pf_change_a(&pd->dst->v4.s_addr, pd->ip_sum,
+ nk->addr[pd->didx].v4.s_addr, 0);
+ PF_ACPY(&pd->ndaddr, pd->dst, pd->af);
+ }
+
+ if (virtual_type == htons(ICMP_ECHO) &&
+ nk->port[pd->sidx] != pd->hdr.icmp.icmp_id) {
+ pd->hdr.icmp.icmp_cksum = pf_cksum_fixup(
+ pd->hdr.icmp.icmp_cksum, pd->nsport,
+ nk->port[pd->sidx], 0);
+ pd->hdr.icmp.icmp_id = nk->port[pd->sidx];
+ pd->sport = &pd->hdr.icmp.icmp_id;
+ }
+ m_copyback(pd->m, pd->off, ICMP_MINLEN, (caddr_t)&pd->hdr.icmp);
+ break;
+#endif /* INET */
+#ifdef INET6
+ case IPPROTO_ICMPV6:
+ if (PF_ANEQ(&pd->nsaddr, &nk->addr[pd->sidx], AF_INET6)) {
+ pf_change_a6(pd->src, &pd->hdr.icmp6.icmp6_cksum,
+ &nk->addr[pd->sidx], 0);
+ PF_ACPY(&pd->nsaddr, pd->src, pd->af);
+ }
+
+ if (PF_ANEQ(&pd->ndaddr, &nk->addr[pd->didx], AF_INET6)) {
+ pf_change_a6(pd->dst, &pd->hdr.icmp6.icmp6_cksum,
+ &nk->addr[pd->didx], 0);
+ PF_ACPY(&pd->ndaddr, pd->dst, pd->af);
+ }
+ rewrite++;
+ break;
+#endif /* INET */
+ default:
+ switch (pd->af) {
+#ifdef INET
+ case AF_INET:
+ if (PF_ANEQ(&pd->nsaddr,
+ &nk->addr[pd->sidx], AF_INET)) {
+ pf_change_a(&pd->src->v4.s_addr,
+ pd->ip_sum,
+ nk->addr[pd->sidx].v4.s_addr, 0);
+ PF_ACPY(&pd->nsaddr, pd->src, pd->af);
+ }
+
+ if (PF_ANEQ(&pd->ndaddr,
+ &nk->addr[pd->didx], AF_INET)) {
+ pf_change_a(&pd->dst->v4.s_addr,
+ pd->ip_sum,
+ nk->addr[pd->didx].v4.s_addr, 0);
+ PF_ACPY(&pd->ndaddr, pd->dst, pd->af);
+ }
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
+ if (PF_ANEQ(&pd->nsaddr,
+ &nk->addr[pd->sidx], AF_INET6)) {
+ PF_ACPY(&pd->nsaddr, &nk->addr[pd->sidx], pd->af);
+ PF_ACPY(pd->src, &nk->addr[pd->sidx], pd->af);
+ }
+
+ if (PF_ANEQ(&pd->ndaddr,
+ &nk->addr[pd->didx], AF_INET6)) {
+ PF_ACPY(&pd->ndaddr, &nk->addr[pd->didx], pd->af);
+ PF_ACPY(pd->dst, &nk->addr[pd->didx], pd->af);
+ }
+ break;
+#endif /* INET */
+ }
+ break;
+ }
+ return (rewrite);
+}
+
static int
pf_tcp_track_full(struct pf_kstate **state, struct pf_pdesc *pd,
u_short *reason, int *copyback, struct pf_state_peer *src,
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
@@ -75,7 +75,7 @@
static uint64_t pf_hash(struct pf_addr *, struct pf_addr *,
struct pf_poolhashkey *, sa_family_t);
-static struct pf_krule *pf_match_translation(struct pf_pdesc *,
+struct pf_krule *pf_match_translation(struct pf_pdesc *,
int, struct pf_kanchor_stackframe *);
static int pf_get_sport(struct pf_pdesc *, struct pf_krule *,
struct pf_addr *, uint16_t *, uint16_t, uint16_t,
@@ -126,7 +126,7 @@
return (res);
}
-static struct pf_krule *
+struct pf_krule *
pf_match_translation(struct pf_pdesc *pd,
int rs_num, struct pf_kanchor_stackframe *anchor_stack)
{
@@ -422,19 +422,19 @@
pf_get_mape_sport(struct pf_pdesc *pd, struct pf_krule *r,
struct pf_addr *naddr, uint16_t *nport,
struct pf_ksrc_node **sn, struct pf_srchash **sh,
- struct pf_udp_mapping **udp_mapping)
+ struct pf_udp_mapping **udp_mapping, struct pf_kpool *rpool)
{
uint16_t psmask, low, highmask;
uint16_t i, ahigh, cut;
int ashift, psidshift;
- ashift = 16 - r->rdr.mape.offset;
- psidshift = ashift - r->rdr.mape.psidlen;
- psmask = r->rdr.mape.psid & ((1U << r->rdr.mape.psidlen) - 1);
+ ashift = 16 - rpool->mape.offset;
+ psidshift = ashift - rpool->mape.psidlen;
+ psmask = rpool->mape.psid & ((1U << rpool->mape.psidlen) - 1);
psmask = psmask << psidshift;
highmask = (1U << psidshift) - 1;
- ahigh = (1U << r->rdr.mape.offset) - 1;
+ ahigh = (1U << rpool->mape.offset) - 1;
cut = arc4random() & ahigh;
if (cut == 0)
cut = 1;
@@ -442,14 +442,14 @@
for (i = cut; i <= ahigh; i++) {
low = (i << ashift) | psmask;
if (!pf_get_sport(pd, r,
- naddr, nport, low, low | highmask, sn, sh, &r->rdr,
+ naddr, nport, low, low | highmask, sn, sh, rpool,
udp_mapping, PF_SN_NAT))
return (0);
}
for (i = cut - 1; i > 0; i--) {
low = (i << ashift) | psmask;
if (!pf_get_sport(pd, r,
- naddr, nport, low, low | highmask, sn, sh, &r->rdr,
+ naddr, nport, low, low | highmask, sn, sh, rpool,
udp_mapping, PF_SN_NAT))
return (0);
}
@@ -768,12 +768,7 @@
struct pf_udp_mapping **udp_mapping)
{
struct pf_krule *r = NULL;
- struct pf_addr *naddr;
- struct pf_ksrc_node *sn = NULL;
- struct pf_srchash *sh = NULL;
- uint16_t *nportp;
- uint16_t low, high;
- u_short reason;
+ u_short transerror;
PF_RULES_RASSERT();
KASSERT(*skp == NULL, ("*skp not NULL"));
@@ -801,38 +796,64 @@
return (PFRES_MAX);
}
- if (pf_state_key_setup(pd, pd->nsport, pd->ndport, skp, nkp))
- return (PFRES_MEMORY);
+ transerror = pf_get_transaddr(pd, skp, nkp, r, udp_mapping, r->action, &(r->rdr));
+ if (transerror == PFRES_MATCH)
+ *rp = r;
+
+ return (transerror);
+}
+
+u_short
+pf_get_transaddr(struct pf_pdesc *pd, struct pf_state_key **skp,
+ struct pf_state_key **nkp, struct pf_krule *r,
+ struct pf_udp_mapping **udp_mapping, u_int8_t nat_action,
+ struct pf_kpool *rpool)
+{
+ struct pf_addr *naddr;
+ struct pf_ksrc_node *sn = NULL;
+ struct pf_srchash *sh = NULL;
+ uint16_t *nportp;
+ uint16_t low, high;
+ u_short reason;
+
+ PF_RULES_RASSERT();
+ KASSERT(r != NULL, ("r is NULL"));
+ KASSERT(!(r->rule_flag & PFRULE_AFTO), ("AFTO rule"));
+
+ if (*skp == NULL && *nkp == NULL) {
+ if (pf_state_key_setup(pd, pd->nsport, pd->ndport, skp, nkp))
+ return (PFRES_MEMORY);
+ }
naddr = &(*nkp)->addr[1];
nportp = &(*nkp)->port[1];
- switch (r->action) {
+ switch (nat_action) {
case PF_NAT:
if (pd->proto == IPPROTO_ICMP) {
low = 1;
high = 65535;
} else {
- low = r->rdr.proxy_port[0];
- high = r->rdr.proxy_port[1];
+ low = rpool->proxy_port[0];
+ high = rpool->proxy_port[1];
}
- if (r->rdr.mape.offset > 0) {
+ if (rpool->mape.offset > 0) {
if (pf_get_mape_sport(pd, r, naddr, nportp, &sn,
- &sh, udp_mapping)) {
+ &sh, udp_mapping, rpool)) {
DPFPRINTF(PF_DEBUG_MISC,
("pf: MAP-E port allocation (%u/%u/%u)"
" failed\n",
- r->rdr.mape.offset,
- r->rdr.mape.psidlen,
- r->rdr.mape.psid));
+ rpool->mape.offset,
+ rpool->mape.psidlen,
+ rpool->mape.psid));
reason = PFRES_MAPFAILED;
goto notrans;
}
} else if (pf_get_sport(pd, r, naddr, nportp, low, high, &sn,
- &sh, &r->rdr, udp_mapping, PF_SN_NAT)) {
+ &sh, rpool, udp_mapping, PF_SN_NAT)) {
DPFPRINTF(PF_DEBUG_MISC,
("pf: NAT proxy port allocation (%u-%u) failed\n",
- r->rdr.proxy_port[0], r->rdr.proxy_port[1]));
+ rpool->proxy_port[0], rpool->proxy_port[1]));
reason = PFRES_MAPFAILED;
goto notrans;
}
@@ -840,41 +861,39 @@
case PF_BINAT:
switch (pd->dir) {
case PF_OUT:
- if (r->rdr.cur->addr.type == PF_ADDR_DYNIFTL){
+ if (rpool->cur->addr.type == PF_ADDR_DYNIFTL){
switch (pd->af) {
#ifdef INET
case AF_INET:
- if (r->rdr.cur->addr.p.dyn->
+ if (rpool->cur->addr.p.dyn->
pfid_acnt4 < 1) {
reason = PFRES_MAPFAILED;
goto notrans;
}
PF_POOLMASK(naddr,
- &r->rdr.cur->addr.p.dyn->
- pfid_addr4,
- &r->rdr.cur->addr.p.dyn->
- pfid_mask4, &pd->nsaddr, AF_INET);
+ &rpool->cur->addr.p.dyn->pfid_addr4,
+ &rpool->cur->addr.p.dyn->pfid_mask4,
+ &pd->nsaddr, AF_INET);
break;
#endif /* INET */
#ifdef INET6
case AF_INET6:
- if (r->rdr.cur->addr.p.dyn->
+ if (rpool->cur->addr.p.dyn->
pfid_acnt6 < 1) {
reason = PFRES_MAPFAILED;
goto notrans;
}
PF_POOLMASK(naddr,
- &r->rdr.cur->addr.p.dyn->
- pfid_addr6,
- &r->rdr.cur->addr.p.dyn->
- pfid_mask6, &pd->nsaddr, AF_INET6);
+ &rpool->cur->addr.p.dyn->pfid_addr6,
+ &rpool->cur->addr.p.dyn->pfid_mask6,
+ &pd->nsaddr, AF_INET6);
break;
#endif /* INET6 */
}
} else
PF_POOLMASK(naddr,
- &r->rdr.cur->addr.v.a.addr,
- &r->rdr.cur->addr.v.a.mask, &pd->nsaddr,
+ &rpool->cur->addr.v.a.addr,
+ &rpool->cur->addr.v.a.mask, &pd->nsaddr,
pd->af);
break;
case PF_IN:
@@ -917,30 +936,30 @@
uint16_t cut, low, high, nport;
reason = pf_map_addr_sn(pd->af, r, &pd->nsaddr, naddr, NULL,
- NULL, &sn, &sh, &r->rdr, PF_SN_NAT);
+ NULL, &sn, &sh, rpool, PF_SN_NAT);
if (reason != 0)
goto notrans;
- if ((r->rdr.opts & PF_POOL_TYPEMASK) == PF_POOL_BITMASK)
- PF_POOLMASK(naddr, naddr, &r->rdr.cur->addr.v.a.mask,
+ if ((rpool->opts & PF_POOL_TYPEMASK) == PF_POOL_BITMASK)
+ PF_POOLMASK(naddr, naddr, &rpool->cur->addr.v.a.mask,
&pd->ndaddr, pd->af);
/* Do not change SCTP ports. */
if (pd->proto == IPPROTO_SCTP)
break;
- if (r->rdr.proxy_port[1]) {
+ if (rpool->proxy_port[1]) {
uint32_t tmp_nport;
tmp_nport = ((ntohs(pd->ndport) - ntohs(r->dst.port[0])) %
- (r->rdr.proxy_port[1] - r->rdr.proxy_port[0] +
- 1)) + r->rdr.proxy_port[0];
+ (rpool->proxy_port[1] - rpool->proxy_port[0] +
+ 1)) + rpool->proxy_port[0];
/* Wrap around if necessary. */
if (tmp_nport > 65535)
tmp_nport -= 65535;
nport = htons((uint16_t)tmp_nport);
- } else if (r->rdr.proxy_port[0])
- nport = htons(r->rdr.proxy_port[0]);
+ } else if (rpool->proxy_port[0])
+ nport = htons(rpool->proxy_port[0]);
else
nport = pd->ndport;
@@ -1015,7 +1034,6 @@
/* Return success only if translation really happened. */
if (bcmp(*skp, *nkp, sizeof(struct pf_state_key_cmp))) {
- *rp = r;
return (PFRES_MATCH);
}
@@ -1028,6 +1046,7 @@
return (reason);
}
+
int
pf_get_transaddr_af(struct pf_krule *r, struct pf_pdesc *pd)
{
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
@@ -21,7 +21,6 @@
loginterface \
killstate \
macro \
- map_e \
match \
max_states \
mbuf \
diff --git a/tests/sys/netpfil/pf/map_e.sh b/tests/sys/netpfil/pf/map_e.sh
deleted file mode 100644
--- a/tests/sys/netpfil/pf/map_e.sh
+++ /dev/null
@@ -1,90 +0,0 @@
-#
-# SPDX-License-Identifier: BSD-2-Clause
-#
-# Copyright (c) 2021 KUROSAWA Takahiro <takahiro.kurosawa@gmail.com>
-#
-# 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 -p ${PWD}/inetd-echo.pid $(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" \
- "set skip on lo"
-
- 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
-}
-
-map_e_cleanup()
-{
- pft_cleanup
-}
-
-atf_init_test_cases()
-{
- atf_add_test_case "map_e"
-}
diff --git a/tests/sys/netpfil/pf/nat.sh b/tests/sys/netpfil/pf/nat.sh
--- a/tests/sys/netpfil/pf/nat.sh
+++ b/tests/sys/netpfil/pf/nat.sh
@@ -2,6 +2,8 @@
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (c) 2018 Kristof Provost <kp@FreeBSD.org>
+# Copyright (c) 2025 Kajetan Staszkiewicz <ks@FreeBSD.org>
+# Copyright (c) 2021 KUROSAWA Takahiro <takahiro.kurosawa@gmail.com>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
@@ -112,14 +114,7 @@
}
-atf_test_case "endpoint_independent" "cleanup"
-endpoint_independent_head()
-{
- atf_set descr 'Test that a client behind NAT gets the same external IP:port for different servers'
- atf_set require.user root
-}
-
-endpoint_independent_body()
+endpoint_independent_setup()
{
pft_init
filter="udp and dst port 1234" # only capture udp pings
@@ -153,13 +148,15 @@
jexec server1 ifconfig ${epair_server1}a 198.51.100.32/24 up
jexec server2 ifconfig ${epair_server2}a 198.51.100.22/24 up
+}
+endpoint_independent_common()
+{
# Enable pf!
jexec nat pfctl -e
# validate non-endpoint independent nat rule behaviour
- pft_set_rules nat \
- "nat on ${epair_nat}a inet from ! (${epair_nat}a) to any -> (${epair_nat}a)"
+ pft_set_rules nat "${1}"
jexec server1 tcpdump -i ${epair_server1}a -w ${PWD}/server1.pcap \
--immediate-mode $filter &
@@ -198,8 +195,7 @@
fi
# validate endpoint independent nat rule behaviour
- pft_set_rules nat \
- "nat on ${epair_nat}a inet from ! (${epair_nat}a) to any -> (${epair_nat}a) endpoint-independent"
+ pft_set_rules nat "${2}"
jexec server1 tcpdump -i ${epair_server1}a -w ${PWD}/server1.pcap \
--immediate-mode $filter &
@@ -238,7 +234,47 @@
fi
}
-endpoint_independent_cleanup()
+atf_test_case "endpoint_independent_compat" "cleanup"
+endpoint_independent_compat_head()
+{
+ atf_set descr 'Test that a client behind NAT gets the same external IP:port for different servers'
+ atf_set require.user root
+}
+
+endpoint_independent_compat_body()
+{
+ endpoint_independent_setup # Sets ${epair_…} variables
+
+ endpoint_independent_common \
+ "nat on ${epair_nat}a inet from ! (${epair_nat}a) to any -> (${epair_nat}a)" \
+ "nat on ${epair_nat}a inet from ! (${epair_nat}a) to any -> (${epair_nat}a) endpoint-independent"
+}
+
+endpoint_independent_compat_cleanup()
+{
+ pft_cleanup
+ rm -f server1.out
+ rm -f server2.out
+}
+
+atf_test_case "endpoint_independent_pass" "cleanup"
+endpoint_independent_pass_head()
+{
+ atf_set descr 'Test that a client behind NAT gets the same external IP:port for different servers'
+ atf_set require.user root
+}
+
+endpoint_independent_pass_body()
+{
+ endpoint_independent_setup # Sets ${epair_…} variables
+
+ endpoint_independent_common \
+ "pass out on ${epair_nat}a inet from ! (${epair_nat}a) to any nat-to (${epair_nat}a) keep state" \
+ "pass out on ${epair_nat}a inet from ! (${epair_nat}a) to any nat-to (${epair_nat}a) endpoint-independent keep state"
+
+}
+
+endpoint_independent_pass_cleanup()
{
pft_cleanup
rm -f server1.out
@@ -438,14 +474,189 @@
pft_cleanup
}
+nat_pass_head()
+{
+ atf_set descr 'IPv4 NAT on pass rule'
+ atf_set require.user root
+ atf_set require.progs scapy
+}
+
+nat_pass_body()
+{
+ setup_router_server_ipv4
+ # Delete the route back to make sure that the traffic has been NAT-ed
+ jexec server route del -net ${net_tester} ${net_server_host_router}
+
+ pft_set_rules router \
+ "block" \
+ "pass in on ${epair_tester}b inet proto tcp keep state" \
+ "pass out on ${epair_server}a inet proto tcp nat-to ${epair_server}a keep state"
+
+ ping_server_check_reply exit:0 --ping-type=tcp3way --send-sport=4201
+
+ jexec router pfctl -qvvsr
+ jexec router pfctl -qvvss
+ jexec router ifconfig
+ jexec router netstat -rn
+}
+
+nat_pass_cleanup()
+{
+ pft_cleanup
+}
+
+nat_match_head()
+{
+ atf_set descr 'IPv4 NAT on match rule'
+ atf_set require.user root
+ atf_set require.progs scapy
+}
+
+nat_match_body()
+{
+ setup_router_server_ipv4
+ # Delete the route back to make sure that the traffic has been NAT-ed
+ jexec server route del -net ${net_tester} ${net_server_host_router}
+
+ # NAT is applied during ruleset evaluation:
+ # rules after "match" match on NAT-ed address
+ pft_set_rules router \
+ "block" \
+ "pass in on ${epair_tester}b inet proto tcp keep state" \
+ "match out on ${epair_server}a inet proto tcp nat-to ${epair_server}a" \
+ "pass out on ${epair_server}a inet proto tcp from ${epair_server}a keep state"
+
+ ping_server_check_reply exit:0 --ping-type=tcp3way --send-sport=4201
+
+ jexec router pfctl -qvvsr
+ jexec router pfctl -qvvss
+ jexec router ifconfig
+ jexec router netstat -rn
+}
+
+nat_match_cleanup()
+{
+ pft_cleanup
+}
+
+map_e_common()
+{
+ 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 -p ${PWD}/inetd-echo.pid $(atf_get_srcdir)/echo_inetd.conf
+
+ # Enable pf!
+ jexec map_e pfctl -e
+}
+
+atf_test_case "map_e_compat" "cleanup"
+map_e_compat_head()
+{
+ atf_set descr 'map-e-portset test'
+ atf_set require.user root
+}
+
+map_e_compat_body()
+{
+ map_e_common
+
+ 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" \
+ "set skip on lo"
+
+ 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
+}
+
+map_e_compat_cleanup()
+{
+ pft_cleanup
+}
+
+
+atf_test_case "map_e_pass" "cleanup"
+map_e_pass_head()
+{
+ atf_set descr 'map-e-portset test'
+ atf_set require.user root
+}
+
+map_e_pass_body()
+{
+ map_e_common
+
+ pft_set_rules map_e \
+ "pass out on ${epair_echo}a inet from 192.0.2.0/24 to any nat-to (${epair_echo}a) map-e-portset 2/12/0x342 keep state"
+
+ jexec map_e pfctl -qvvsr
+
+ # 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" \
+ "set skip on lo"
+
+ 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
+}
+
+map_e_pass_cleanup()
+{
+ pft_cleanup
+}
+
atf_init_test_cases()
{
atf_add_test_case "exhaust"
atf_add_test_case "nested_anchor"
- atf_add_test_case "endpoint_independent"
+ atf_add_test_case "endpoint_independent_compat"
+ atf_add_test_case "endpoint_independent_pass"
atf_add_test_case "nat6_nolinklocal"
atf_add_test_case "empty_table_source_hash"
atf_add_test_case "no_addrs_source_hash"
atf_add_test_case "empty_table_random"
atf_add_test_case "no_addrs_random"
+ atf_add_test_case "map_e_compat"
+ atf_add_test_case "map_e_pass"
+ atf_add_test_case "nat_pass"
+ atf_add_test_case "nat_match"
}
diff --git a/tests/sys/netpfil/pf/rdr.sh b/tests/sys/netpfil/pf/rdr.sh
--- a/tests/sys/netpfil/pf/rdr.sh
+++ b/tests/sys/netpfil/pf/rdr.sh
@@ -27,14 +27,6 @@
. $(atf_get_srcdir)/utils.subr
-atf_test_case "tcp_v6" "cleanup"
-tcp_v6_head()
-{
- atf_set descr 'TCP rdr with IPv6'
- atf_set require.user root
- atf_set require.progs python3
-}
-
#
# Test that rdr works for TCP with IPv6.
#
@@ -47,7 +39,7 @@
#
# Test for incorrect checksums after the rewrite by looking at a packet capture (see bug 210860)
#
-tcp_v6_body()
+tcp_v6_setup()
{
pft_init
@@ -83,9 +75,11 @@
jexec ${j}c route add -inet6 2001:db8:a::0/64 2001:db8:b::1
jexec ${j}b pfctl -e
+}
- pft_set_rules ${j}b \
- "rdr on ${epair_one}a proto tcp from any to any port 80 -> 2001:db8:b::2 port 8000"
+tcp_v6_common()
+{
+ pft_set_rules ${j}b "${1}"
# Check that a can reach c over the router
atf_check -s exit:0 -o ignore \
@@ -116,19 +110,44 @@
atf_check_equal " 0" "$count"
}
-tcp_v6_cleanup()
+atf_test_case "tcp_v6_compat" "cleanup"
+tcp_v6_compat_head()
+{
+ atf_set descr 'TCP rdr with IPv6 with NAT rules'
+ atf_set require.user root
+ atf_set require.progs python3
+}
+
+tcp_v6_compat_body()
+{
+ tcp_v6_setup # Sets ${epair_…} variables
+ tcp_v6_common \
+ "rdr on ${epair_one}a proto tcp from any to any port 80 -> 2001:db8:b::2 port 8000"
+}
+
+tcp_v6_compat_cleanup()
{
pft_cleanup
}
-
-atf_test_case "srcport" "cleanup"
-srcport_head()
+atf_test_case "tcp_v6_pass" "cleanup"
+tcp_v6_pass_head()
{
- atf_set descr 'TCP rdr srcport modulation'
+ atf_set descr 'TCP rdr with IPv6 with pass/match rules'
atf_set require.user root
atf_set require.progs python3
- atf_set timeout 9999
+}
+
+tcp_v6_pass_body()
+{
+ tcp_v6_setup # Sets ${epair_…} variables
+ tcp_v6_common \
+ "rdr on ${epair_one}a proto tcp from any to any port 80 -> 2001:db8:b::2 port 8000"
+}
+
+tcp_v6_pass_cleanup()
+{
+ pft_cleanup
}
#
@@ -145,7 +164,7 @@
# In this case, the rdr rule should also rewrite the source port (again) to
# resolve the state conflict.
#
-srcport_body()
+srcport_setup()
{
pft_init
@@ -188,14 +207,17 @@
jexec ${j}c sysctl net.inet.ip.forwarding=1
jexec ${j}b pfctl -e
jexec ${j}c pfctl -e
+}
+srcport_common()
+{
pft_set_rules ${j}b \
"set debug misc" \
- "nat on ${epair2}a inet from 198.51.100.0/24 to any -> ${epair2}a static-port"
+ "${1}"
pft_set_rules ${j}c \
"set debug misc" \
- "rdr on ${epair2}b proto tcp from any to ${epair2}b port 7777 -> 203.0.113.50 port 8888"
+ "${2}"
jexec ${j}a route add default 198.51.100.1
jexec ${j}c route add 198.51.100.0/24 198.51.101.2
@@ -215,13 +237,54 @@
atf_check -o match:"[0-9]+" -o not-inline:"1234" cat port3
}
-srcport_cleanup()
+atf_test_case "srcport_compat" "cleanup"
+srcport_compat_head()
+{
+ atf_set descr 'TCP rdr srcport modulation with NAT rules'
+ atf_set require.user root
+ atf_set require.progs python3
+ atf_set timeout 9999
+}
+
+srcport_compat_body()
+{
+ srcport_setup # Sets ${epair_…} variables
+ srcport_common \
+ "nat on ${epair2}a inet from 198.51.100.0/24 to any -> ${epair2}a static-port" \
+ "rdr on ${epair2}b proto tcp from any to ${epair2}b port 7777 -> 203.0.113.50 port 8888"
+}
+
+srcport_compat_cleanup()
+{
+ pft_cleanup
+}
+
+atf_test_case "srcport_pass" "cleanup"
+srcport_pass_head()
+{
+ atf_set descr 'TCP rdr srcport modulation with pass/match rules'
+ atf_set require.user root
+ atf_set require.progs python3
+ atf_set timeout 9999
+}
+
+srcport_pass_body()
+{
+ srcport_setup # Sets ${epair_…} variables
+ srcport_common \
+ "pass out on ${epair2}a inet from 198.51.100.0/24 to any nat-to ${epair2}a static-port" \
+ "pass in on ${epair2}b proto tcp from any to ${epair2}b port 7777 rdr-to 203.0.113.50 port 8888"
+}
+
+srcport_pass_cleanup()
{
pft_cleanup
}
atf_init_test_cases()
{
- atf_add_test_case "tcp_v6"
- atf_add_test_case "srcport"
+ atf_add_test_case "tcp_v6_compat"
+ atf_add_test_case "tcp_v6_pass"
+ atf_add_test_case "srcport_compat"
+ atf_add_test_case "srcport_pass"
}
diff --git a/tests/sys/netpfil/pf/src_track.sh b/tests/sys/netpfil/pf/src_track.sh
--- a/tests/sys/netpfil/pf/src_track.sh
+++ b/tests/sys/netpfil/pf/src_track.sh
@@ -307,14 +307,14 @@
pft_cleanup
}
-route_to_head()
+sn_types_compat_head()
{
- atf_set descr 'Max states per source per rule with route-to'
+ atf_set descr 'Combination of source node types with compat NAT rules'
atf_set require.user root
atf_set require.progs python3 scapy
}
-route_to_body()
+sn_types_compat_body()
{
setup_router_dummy_ipv6
@@ -398,11 +398,110 @@
! grep -q 'filter rule 3' $nodes || atf_fail "Source node found for rule 3"
}
-route_to_cleanup()
+sn_types_compat_cleanup()
{
pft_cleanup
}
+sn_types_pass_head()
+{
+ atf_set descr 'Combination of source node types with pass NAT rules'
+ atf_set require.user root
+ atf_set require.progs python3 scapy
+}
+
+sn_types_pass_body()
+{
+ setup_router_dummy_ipv6
+
+ # Clients will connect from another network behind the router.
+ # This allows for using multiple source addresses.
+ jexec router route add -6 2001:db8:44::0/64 2001:db8:42::2
+
+ # Additional gateways for route-to.
+ rtgw=${net_server_host_server%::*}::2:1
+ jexec router ndp -s ${rtgw} 00:01:02:03:04:05
+
+ # This test will check for proper source node creation for:
+ # max-src-states -> PF_SN_LIMIT
+ # sticky-address -> PF_SN_NAT
+ # route-to -> PF_SN_ROUTE
+ # The test expands to all 8 combinations of those source nodes being
+ # present or not.
+
+ pft_set_rules router \
+ "table <rtgws> { ${rtgw} }" \
+ "table <rdrgws> { 2001:db8:45::1 }" \
+ "block" \
+ "pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \
+ "match in on ${epair_tester}b inet6 proto tcp from 2001:db8:44::10/124 to 2001:db8:45::1 rdr-to <rdrgws> port 4242 sticky-address label rule_3" \
+ "pass in quick on ${epair_tester}b route-to ( ${epair_server}a <rtgws>) inet6 proto tcp from port 4211 keep state label rule_4" \
+ "pass in quick on ${epair_tester}b route-to ( ${epair_server}a <rtgws>) sticky-address inet6 proto tcp from port 4212 keep state label rule_5" \
+ "pass in quick on ${epair_tester}b route-to ( ${epair_server}a <rtgws>) inet6 proto tcp from port 4213 keep state (max-src-states 3 source-track rule) label rule_6" \
+ "pass in quick on ${epair_tester}b route-to ( ${epair_server}a <rtgws>) sticky-address inet6 proto tcp from port 4214 keep state (max-src-states 3 source-track rule) label rule_7" \
+ "pass out quick on ${epair_server}a keep state"
+
+ # We don't check if state limits are properly enforced, this is tested
+ # by other tests in this file.
+ # Source address will not match the NAT rule
+ ping_dummy_check_request exit:0 --ping-type=tcpsyn --send-sport=4211 --fromaddr 2001:db8:44::01 --to 2001:db8:45::1
+ ping_dummy_check_request exit:0 --ping-type=tcpsyn --send-sport=4212 --fromaddr 2001:db8:44::02 --to 2001:db8:45::1
+ ping_dummy_check_request exit:0 --ping-type=tcpsyn --send-sport=4213 --fromaddr 2001:db8:44::03 --to 2001:db8:45::1
+ ping_dummy_check_request exit:0 --ping-type=tcpsyn --send-sport=4214 --fromaddr 2001:db8:44::04 --to 2001:db8:45::1
+ # Source address will match the NAT rule
+ ping_dummy_check_request exit:0 --ping-type=tcpsyn --send-sport=4211 --fromaddr 2001:db8:44::11 --to 2001:db8:45::1
+ ping_dummy_check_request exit:0 --ping-type=tcpsyn --send-sport=4212 --fromaddr 2001:db8:44::12 --to 2001:db8:45::1
+ ping_dummy_check_request exit:0 --ping-type=tcpsyn --send-sport=4213 --fromaddr 2001:db8:44::13 --to 2001:db8:45::1
+ ping_dummy_check_request exit:0 --ping-type=tcpsyn --send-sport=4214 --fromaddr 2001:db8:44::14 --to 2001:db8:45::1
+
+ states=$(mktemp) || exit 1
+ jexec router pfctl -qvss | normalize_pfctl_s > $states
+ nodes=$(mktemp) || exit 1
+ jexec router pfctl -qvvsS | normalize_pfctl_s > $nodes
+
+ echo " === states ==="
+ cat $states
+ echo " === nodes ==="
+ cat $nodes
+ echo " === end === "
+
+ # Order of states in output is not guaranteed, find each one separately.
+ for state_regexp in \
+ 'all tcp 2001:db8:45::1\[9\] <- 2001:db8:44::1\[4211\] .* 1:0 pkts, 76:0 bytes, rule 4$' \
+ 'all tcp 2001:db8:45::1\[9\] <- 2001:db8:44::2\[4212\] .* 1:0 pkts, 76:0 bytes, rule 5, route sticky-address$' \
+ 'all tcp 2001:db8:45::1\[9\] <- 2001:db8:44::3\[4213\] .* 1:0 pkts, 76:0 bytes, rule 6, limit source-track$' \
+ 'all tcp 2001:db8:45::1\[9\] <- 2001:db8:44::4\[4214\] .* 1:0 pkts, 76:0 bytes, rule 7, limit source-track, route sticky-address$' \
+ 'all tcp 2001:db8:45::1\[4242\] \(2001:db8:45::1\[9\]\) <- 2001:db8:44::11\[4211\] .* 1:0 pkts, 76:0 bytes, rule 4, NAT/RDR sticky-address' \
+ 'all tcp 2001:db8:45::1\[4242\] \(2001:db8:45::1\[9\]\) <- 2001:db8:44::12\[4212\] .* 1:0 pkts, 76:0 bytes, rule 5, NAT/RDR sticky-address, route sticky-address' \
+ 'all tcp 2001:db8:45::1\[4242\] \(2001:db8:45::1\[9\]\) <- 2001:db8:44::13\[4213\] .* 1:0 pkts, 76:0 bytes, rule 6, limit source-track, NAT/RDR sticky-address' \
+ 'all tcp 2001:db8:45::1\[4242\] \(2001:db8:45::1\[9\]\) <- 2001:db8:44::14\[4214\] .* 1:0 pkts, 76:0 bytes, rule 7, limit source-track, NAT/RDR sticky-address, route sticky-address' \
+ ; do
+ grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'"
+ done
+
+ # Order of source nodes in output is not guaranteed, find each one separately.
+ for node_regexp in \
+ '2001:db8:44::2 -> 2001:db8:43::2:1 \( states 1, connections 0, rate 0.0/0s \) age [0-9:]+, 1 pkts, 76 bytes, filter rule 5, route sticky-address' \
+ '2001:db8:44::3 -> :: \( states 1, connections 0, rate 0.0/0s \) age [0-9:]+, 1 pkts, 76 bytes, filter rule 6, limit source-track' \
+ '2001:db8:44::4 -> 2001:db8:43::2:1 \( states 1, connections 0, rate 0.0/0s ) age [0-9:]+, 1 pkts, 76 bytes, filter rule 7, route sticky-address' \
+ '2001:db8:44::4 -> :: \( states 1, connections 0, rate 0.0/0s \) age [0-9:]+, 1 pkts, 76 bytes, filter rule 7, limit source-track' \
+ '2001:db8:44::11 -> 2001:db8:45::1 \( states 1, connections 0, rate 0.0/0s \) age [0-9:]+, 1 pkts, 76 bytes, filter rule 3, NAT/RDR sticky-address' \
+ '2001:db8:44::12 -> 2001:db8:45::1 \( states 1, connections 0, rate 0.0/0s \) age [0-9:]+, 1 pkts, 76 bytes, filter rule 3, NAT/RDR sticky-address' \
+ '2001:db8:44::12 -> 2001:db8:43::2:1 \( states 1, connections 0, rate 0.0/0s \) age [0-9:]+, 1 pkts, 76 bytes, filter rule 5, route sticky-address' \
+ '2001:db8:44::13 -> 2001:db8:45::1 \( states 1, connections 0, rate 0.0/0s \) age [0-9:]+, 1 pkts, 76 bytes, filter rule 3, NAT/RDR sticky-address' \
+ '2001:db8:44::13 -> :: \( states 1, connections 0, rate 0.0/0s \) age [0-9:]+, 1 pkts, 76 bytes, filter rule 6, limit source-track' \
+ '2001:db8:44::14 -> 2001:db8:45::1 \( states 1, connections 0, rate 0.0/0s \) age [0-9:]+, 1 pkts, 76 bytes, filter rule 3, NAT/RDR sticky-address' \
+ '2001:db8:44::14 -> 2001:db8:43::2:1 \( states 1, connections 0, rate 0.0/0s ) age [0-9:]+, 1 pkts, 76 bytes, filter rule 7, route sticky-address' \
+ '2001:db8:44::14 -> :: \( states 1, connections 0, rate 0.0/0s \) age [0-9:]+, 1 pkts, 76 bytes, filter rule 7, limit source-track' \
+ ; do
+ grep -qE "${node_regexp}" $nodes || atf_fail "Source node not found for '${node_regexp}'"
+ done
+}
+
+sn_types_pass_cleanup()
+{
+ pft_cleanup
+}
atf_init_test_cases()
{
@@ -411,5 +510,6 @@
atf_add_test_case "max_src_conn_rule"
atf_add_test_case "max_src_states_rule"
atf_add_test_case "max_src_states_global"
- atf_add_test_case "route_to"
+ atf_add_test_case "sn_types_compat"
+ atf_add_test_case "sn_types_pass"
}

File Metadata

Mime Type
text/plain
Expires
Wed, Mar 5, 6:43 PM (16 h, 40 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16999322
Default Alt Text
D49221.diff (55 KB)

Event Timeline