Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F139396122
D51659.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
32 KB
Referenced Files
None
Subscribers
None
D51659.diff
View Options
diff --git a/lib/libpfctl/libpfctl.h b/lib/libpfctl/libpfctl.h
--- a/lib/libpfctl/libpfctl.h
+++ b/lib/libpfctl/libpfctl.h
@@ -143,9 +143,18 @@
int match; /* XXX: used for pfctl black magic */
};
+struct pfctl_pooladdr {
+ struct pf_addr_wrap addr;
+ TAILQ_ENTRY(pfctl_pooladdr) entries;
+ char ifname[IFNAMSIZ];
+ sa_family_t af;
+};
+
+TAILQ_HEAD(pfctl_palist, pfctl_pooladdr);
+
struct pfctl_pool {
- struct pf_palist list;
- struct pf_pooladdr *cur;
+ struct pfctl_palist list;
+ struct pfctl_pooladdr *cur;
struct pf_poolhashkey key;
struct pf_addr counter;
struct pf_mape_portset mape;
@@ -383,6 +392,7 @@
uint8_t set_prio[2];
uint8_t rt;
char rt_ifname[IFNAMSIZ];
+ sa_family_t rt_af;
uint8_t src_node_flags;
};
@@ -414,7 +424,7 @@
uint32_t states;
uint32_t conn;
sa_family_t af;
- sa_family_t naf;
+ sa_family_t raf;
uint8_t ruletype;
uint64_t creation;
uint64_t expire;
diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c
--- a/lib/libpfctl/libpfctl.c
+++ b/lib/libpfctl/libpfctl.c
@@ -1940,6 +1940,7 @@
{ .type = PF_ST_RT, .off = _OUT(rt), .cb = snl_attr_get_uint8 },
{ .type = PF_ST_RT_IFNAME, .off = _OUT(rt_ifname), .cb = snl_attr_store_ifname },
{ .type = PF_ST_SRC_NODE_FLAGS, .off = _OUT(src_node_flags), .cb = snl_attr_get_uint8 },
+ { .type = PF_ST_RT_AF, .off = _OUT(rt_af), .cb = snl_attr_get_uint8 },
};
#undef _IN
#undef _OUT
@@ -3043,7 +3044,7 @@
{ .type = PF_SN_CREATION, .off = _OUT(creation), .cb = snl_attr_get_uint64 },
{ .type = PF_SN_EXPIRE, .off = _OUT(expire), .cb = snl_attr_get_uint64 },
{ .type = PF_SN_CONNECTION_RATE, .off = _OUT(conn_rate), .arg = &pfctl_threshold_parser, .cb = snl_attr_get_nested },
- { .type = PF_SN_NAF, .off = _OUT(naf), .cb = snl_attr_get_uint8 },
+ { .type = PF_SN_RAF, .off = _OUT(raf), .cb = snl_attr_get_uint8 },
{ .type = PF_SN_NODE_TYPE, .off = _OUT(type), .cb = snl_attr_get_uint8 },
};
#undef _OUT
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -4852,7 +4852,7 @@
tagged rtable binat_redirspec
{
struct pfctl_rule binat;
- struct pf_pooladdr *pa;
+ struct pfctl_pooladdr *pa;
if (check_rulestate(PFCTL_STATE_NAT))
YYERROR;
@@ -5011,11 +5011,12 @@
YYERROR;
}
- pa = calloc(1, sizeof(struct pf_pooladdr));
+ pa = calloc(1, sizeof(struct pfctl_pooladdr));
if (pa == NULL)
err(1, "binat: calloc");
pa->addr = $13->host->addr;
pa->ifname[0] = 0;
+ pa->af = $13->host->af;
TAILQ_INSERT_TAIL(&binat.rdr.list,
pa, entries);
@@ -6115,7 +6116,7 @@
apply_redirspec(struct pfctl_pool *rpool, struct redirspec *rs)
{
struct node_host *h;
- struct pf_pooladdr *pa;
+ struct pfctl_pooladdr *pa;
if (rs == NULL)
return 0;
@@ -6155,10 +6156,11 @@
sizeof(struct pf_poolhashkey));
for (h = rs->host; h != NULL; h = h->next) {
- pa = calloc(1, sizeof(struct pf_pooladdr));
+ pa = calloc(1, sizeof(struct pfctl_pooladdr));
if (pa == NULL)
err(1, "%s: calloc", __func__);
pa->addr = h->addr;
+ pa->af = h->af;
if (h->ifname != NULL) {
if (strlcpy(pa->ifname, h->ifname,
sizeof(pa->ifname)) >= sizeof(pa->ifname))
@@ -6175,7 +6177,7 @@
check_binat_redirspec(struct node_host *src_host, struct pfctl_rule *r,
sa_family_t af)
{
- struct pf_pooladdr *nat_pool = TAILQ_FIRST(&(r->nat.list));
+ struct pfctl_pooladdr *nat_pool = TAILQ_FIRST(&(r->nat.list));
int error = 0;
/* XXX: FreeBSD allows syntax like "{ host1 host2 }" for redirection
@@ -6248,7 +6250,7 @@
/*
* We're copying the whole rule, but we must re-init redir pools.
- * FreeBSD uses lists of pf_pooladdr, we can't just overwrite them.
+ * FreeBSD uses lists of pfctl_pooladdr, we can't just overwrite them.
*/
bcopy(binat_rule, rdr_rule, sizeof(struct pfctl_rule));
TAILQ_INIT(&(rdr_rule->rdr.list));
diff --git a/sbin/pfctl/pf_print_state.c b/sbin/pfctl/pf_print_state.c
--- a/sbin/pfctl/pf_print_state.c
+++ b/sbin/pfctl/pf_print_state.c
@@ -113,10 +113,11 @@
if (addr->type != PF_ADDR_RANGE &&
!(PF_AZERO(&addr->v.a.addr, AF_INET6) &&
PF_AZERO(&addr->v.a.mask, AF_INET6))) {
- int bits = unmask(&addr->v.a.mask);
-
- if (bits < (af == AF_INET ? 32 : 128))
- printf("/%d", bits);
+ if (af == AF_INET || af == AF_INET6) {
+ int bits = unmask(&addr->v.a.mask);
+ if (bits < (af == AF_INET ? 32 : 128))
+ printf("/%d", bits);
+ }
}
}
@@ -228,7 +229,6 @@
struct pfctl_state_key *key, *sk, *nk;
const char *protoname;
int min, sec;
- sa_family_t af;
uint8_t proto;
int afto = (s->key[PF_SK_STACK].af != s->key[PF_SK_WIRE].af);
int idx;
@@ -242,7 +242,6 @@
key = s->key;
#endif
- af = s->key[PF_SK_WIRE].af;
proto = s->key[PF_SK_WIRE].proto;
if (s->direction == PF_OUT) {
@@ -430,7 +429,7 @@
default:
printf(" gateway: ");
}
- print_host(&s->rt_addr, 0, af, opts);
+ print_host(&s->rt_addr, 0, s->rt_af, opts);
if (s->rt_ifname[0])
printf("@%s", s->rt_ifname);
}
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -1038,7 +1038,7 @@
u_int32_t ticket, int r_action, const char *anchorname, int which)
{
struct pfioc_pooladdr pp;
- struct pf_pooladdr *pa;
+ struct pfctl_pooladdr *pa;
u_int32_t pnr, mpnr;
int ret;
@@ -1054,10 +1054,11 @@
warnc(ret, "DIOCGETADDR");
return (-1);
}
- pa = calloc(1, sizeof(struct pf_pooladdr));
+ pa = calloc(1, sizeof(struct pfctl_pooladdr));
if (pa == NULL)
err(1, "calloc");
- bcopy(&pp.addr, pa, sizeof(struct pf_pooladdr));
+ bcopy(&pp.addr, pa, sizeof(struct pfctl_pooladdr));
+ pa->af = pp.af;
TAILQ_INSERT_TAIL(&pool->list, pa, entries);
}
@@ -1067,7 +1068,7 @@
void
pfctl_move_pool(struct pfctl_pool *src, struct pfctl_pool *dst)
{
- struct pf_pooladdr *pa;
+ struct pfctl_pooladdr *pa;
while ((pa = TAILQ_FIRST(&src->list)) != NULL) {
TAILQ_REMOVE(&src->list, pa, entries);
@@ -1078,7 +1079,7 @@
void
pfctl_clear_pool(struct pfctl_pool *pool)
{
- struct pf_pooladdr *pa;
+ struct pfctl_pooladdr *pa;
while ((pa = TAILQ_FIRST(&pool->list)) != NULL) {
TAILQ_REMOVE(&pool->list, pa, entries);
@@ -1794,14 +1795,14 @@
/* callbacks for rule/nat/rdr/addr */
int
-pfctl_add_pool(struct pfctl *pf, struct pfctl_pool *p, sa_family_t af, int which)
+pfctl_add_pool(struct pfctl *pf, struct pfctl_pool *p, int which)
{
- struct pf_pooladdr *pa;
+ struct pfctl_pooladdr *pa;
int ret;
- pf->paddr.af = af;
TAILQ_FOREACH(pa, &p->list, entries) {
- memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr));
+ memcpy(&pf->paddr.addr, pa, sizeof(struct pfctl_pooladdr));
+ pf->paddr.af = pa->af;
if ((pf->opts & PF_OPT_NOACTION) == 0) {
if ((ret = pfctl_add_addr(pf->h, &pf->paddr, which)) != 0)
errc(1, ret, "DIOCADDADDR");
@@ -2165,11 +2166,11 @@
errc(1, error, "DIOCBEGINADDRS");
}
- if (pfctl_add_pool(pf, &r->rdr, r->af, PF_RDR))
+ if (pfctl_add_pool(pf, &r->rdr, PF_RDR))
return (1);
- if (pfctl_add_pool(pf, &r->nat, r->naf ? r->naf : r->af, PF_NAT))
+ if (pfctl_add_pool(pf, &r->nat, PF_NAT))
return (1);
- if (pfctl_add_pool(pf, &r->route, r->af, PF_RT))
+ if (pfctl_add_pool(pf, &r->route, PF_RT))
return (1);
error = pfctl_add_rule_h(pf->h, r, anchor, name, ticket,
pf->paddr.ticket);
diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h
--- a/sbin/pfctl/pfctl_parser.h
+++ b/sbin/pfctl/pfctl_parser.h
@@ -286,7 +286,7 @@
int pfctl_append_eth_rule(struct pfctl *, struct pfctl_eth_rule *,
const char *);
int pfctl_add_altq(struct pfctl *, struct pf_altq *);
-int pfctl_add_pool(struct pfctl *, struct pfctl_pool *, sa_family_t, int);
+int pfctl_add_pool(struct pfctl *, struct pfctl_pool *, int);
void pfctl_move_pool(struct pfctl_pool *, struct pfctl_pool *);
void pfctl_clear_pool(struct pfctl_pool *);
@@ -304,7 +304,7 @@
int parse_flags(char *);
int pfctl_load_anchors(int, struct pfctl *, struct pfr_buffer *);
-void print_pool(struct pfctl_pool *, u_int16_t, u_int16_t, sa_family_t, int);
+void print_pool(struct pfctl_pool *, u_int16_t, u_int16_t, int);
void print_src_node(struct pfctl_src_node *, int);
void print_eth_rule(struct pfctl_eth_rule *, const char *, int);
void print_rule(struct pfctl_rule *, const char *, int, int);
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
@@ -429,10 +429,9 @@
}
void
-print_pool(struct pfctl_pool *pool, u_int16_t p1, u_int16_t p2,
- sa_family_t af, int id)
+print_pool(struct pfctl_pool *pool, u_int16_t p1, u_int16_t p2, int id)
{
- struct pf_pooladdr *pooladdr;
+ struct pfctl_pooladdr *pooladdr;
if ((TAILQ_FIRST(&pool->list) != NULL) &&
TAILQ_NEXT(TAILQ_FIRST(&pool->list), entries) != NULL)
@@ -442,15 +441,15 @@
case PF_NAT:
case PF_RDR:
case PF_BINAT:
- print_addr(&pooladdr->addr, af, 0);
+ print_addr(&pooladdr->addr, pooladdr->af, 0);
break;
case PF_PASS:
case PF_MATCH:
- if (PF_AZERO(&pooladdr->addr.v.a.addr, af))
+ if (PF_AZERO(&pooladdr->addr.v.a.addr, pooladdr->af))
printf("%s", pooladdr->ifname);
else {
printf("(%s ", pooladdr->ifname);
- print_addr(&pooladdr->addr, af, 0);
+ print_addr(&pooladdr->addr, pooladdr->af, 0);
printf(")");
}
break;
@@ -674,7 +673,7 @@
print_addr(&aw, sn->af, opts & PF_OPT_VERBOSE2);
printf(" -> ");
aw.v.a.addr = sn->raddr;
- print_addr(&aw, sn->naf ? sn->naf : sn->af, opts & PF_OPT_VERBOSE2);
+ print_addr(&aw, sn->raf, opts & PF_OPT_VERBOSE2);
printf(" ( states %u, connections %u, rate %u.%u/%us )\n", sn->states,
sn->conn, sn->conn_rate.count / 1000,
(sn->conn_rate.count % 1000) / 100, sn->conn_rate.seconds);
@@ -952,10 +951,7 @@
else if (r->rt == PF_DUPTO)
printf(" dup-to");
printf(" ");
- print_pool(&r->rdr, 0, 0, r->af, PF_PASS);
- print_pool(&r->route, 0, 0,
- r->rule_flag & PFRULE_AFTO && r->rt != PF_REPLYTO ? r->naf : r->af,
- PF_PASS);
+ print_pool(&r->route, 0, 0, PF_PASS);
}
if (r->af) {
if (r->af == AF_INET)
@@ -1252,17 +1248,16 @@
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);
+ r->rdr.proxy_port[1], 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");
+ printf(" af-to %s from ", r->naf == AF_INET ? "inet" : (r->naf == AF_INET6 ? "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);
+ r->nat.proxy_port[1], PF_NAT);
}
if (!TAILQ_EMPTY(&r->rdr.list)) {
if (r->rule_flag & PFRULE_AFTO) {
@@ -1271,8 +1266,7 @@
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);
+ r->rdr.proxy_port[1], PF_RDR);
}
}
}
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -629,6 +629,7 @@
struct pf_addr_wrap addr;
TAILQ_ENTRY(pf_kpooladdr) entries;
char ifname[IFNAMSIZ];
+ sa_family_t af;
struct pfi_kkif *kif;
};
@@ -656,6 +657,7 @@
uint16_t max_mss;
uint16_t dnpipe;
uint16_t dnrpipe; /* Reverse direction pipe */
+ sa_family_t rt_af;
uint8_t log;
uint8_t set_tos;
uint8_t min_ttl;
@@ -911,7 +913,7 @@
u_int32_t creation;
u_int32_t expire;
sa_family_t af;
- sa_family_t naf;
+ sa_family_t raf;
u_int8_t ruletype;
pf_sn_types_t type;
struct mtx *lock;
@@ -2717,14 +2719,15 @@
struct pf_keth_rule **, struct pf_keth_rule **,
int *);
-u_short pf_map_addr(u_int8_t, struct pf_krule *,
+u_short pf_map_addr(sa_family_t, struct pf_krule *,
struct pf_addr *, struct pf_addr *,
- struct pfi_kkif **nkif, struct pf_addr *,
- struct pf_kpool *);
+ struct pfi_kkif **nkif, sa_family_t *,
+ struct pf_addr *, struct pf_kpool *);
u_short pf_map_addr_sn(u_int8_t, struct pf_krule *,
struct pf_addr *, struct pf_addr *,
- struct pfi_kkif **nkif, struct pf_addr *,
- struct pf_kpool *, pf_sn_types_t);
+ sa_family_t *, struct pfi_kkif **nkif,
+ struct pf_addr *, struct pf_kpool *,
+ pf_sn_types_t);
int pf_get_transaddr_af(struct pf_krule *,
struct pf_pdesc *);
u_short pf_get_translation(struct pf_test_ctx *);
diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c
--- a/sys/netpfil/pf/if_pfsync.c
+++ b/sys/netpfil/pf/if_pfsync.c
@@ -529,6 +529,7 @@
struct pfi_kkif *rt_kif = NULL;
struct pf_kpooladdr *rpool_first;
int error;
+ sa_family_t rt_af = 0;
uint8_t rt = 0;
int n = 0;
@@ -602,6 +603,11 @@
}
rt = r->rt;
rt_kif = rpool_first->kif;
+ /*
+ * Guess the AF of the route address, FreeBSD 13 does
+ * not support af-to so it should be safe.
+ */
+ rt_af = r->af;
} else if (!PF_AZERO(&sp->pfs_1301.rt_addr, sp->pfs_1301.af)) {
/*
* Ruleset different, routing *supposedly* requested,
@@ -627,6 +633,11 @@
return ((flags & PFSYNC_SI_IOCTL) ? EINVAL : 0);
}
rt = sp->pfs_1400.rt;
+ /*
+ * Guess the AF of the route address, FreeBSD 13 does
+ * not support af-to so it should be safe.
+ */
+ rt_af = sp->pfs_1400.af;
}
break;
}
@@ -706,6 +717,7 @@
st->act.rt = rt;
st->act.rt_kif = rt_kif;
+ st->act.rt_af = rt_af;
switch (msg_version) {
case PFSYNC_MSG_VERSION_1301:
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
@@ -401,7 +401,7 @@
static u_short pf_insert_src_node(struct pf_ksrc_node *[PF_SN_MAX],
struct pf_srchash *[PF_SN_MAX], struct pf_krule *,
struct pf_addr *, sa_family_t, struct pf_addr *,
- struct pfi_kkif *, pf_sn_types_t);
+ struct pfi_kkif *, sa_family_t, pf_sn_types_t);
static u_int pf_purge_expired_states(u_int, int);
static void pf_purge_unlinked_rules(void);
static int pf_mtag_uminit(void *, int, int);
@@ -1017,7 +1017,7 @@
pf_insert_src_node(struct pf_ksrc_node *sns[PF_SN_MAX],
struct pf_srchash *snhs[PF_SN_MAX], struct pf_krule *rule,
struct pf_addr *src, sa_family_t af, struct pf_addr *raddr,
- struct pfi_kkif *rkif, pf_sn_types_t sn_type)
+ struct pfi_kkif *rkif, sa_family_t raf, pf_sn_types_t sn_type)
{
u_short reason = 0;
struct pf_krule *r_track = rule;
@@ -1089,8 +1089,9 @@
(*sn)->rule = r_track;
pf_addrcpy(&(*sn)->addr, src, af);
if (raddr != NULL)
- pf_addrcpy(&(*sn)->raddr, raddr, af);
+ pf_addrcpy(&(*sn)->raddr, raddr, raf);
(*sn)->rkif = rkif;
+ (*sn)->raf = raf;
LIST_INSERT_HEAD(&(*sh)->nodes, *sn, entry);
(*sn)->creation = time_uptime;
(*sn)->ruletype = rule->action;
@@ -5907,9 +5908,13 @@
* it is applied only from the last pass rule.
*/
pd->act.rt = r->rt;
+ if (r->rt == PF_REPLYTO)
+ pd->act.rt_af = pd->af;
+ else
+ pd->act.rt_af = pd->naf;
if ((transerror = pf_map_addr_sn(pd->af, r, pd->src,
- &pd->act.rt_addr, &pd->act.rt_kif, NULL, &(r->route),
- PF_SN_ROUTE)) != PFRES_MATCH) {
+ &pd->act.rt_addr, &pd->act.rt_af, &pd->act.rt_kif, NULL,
+ &(r->route), PF_SN_ROUTE)) != PFRES_MATCH) {
REASON_SET(&ctx.reason, transerror);
goto cleanup;
}
@@ -6039,7 +6044,7 @@
/* src node for limits */
if ((r->rule_flag & PFRULE_SRCTRACK) &&
(sn_reason = pf_insert_src_node(sns, snhs, r, pd->src, pd->af,
- NULL, NULL, PF_SN_LIMIT)) != 0) {
+ NULL, NULL, pd->af, PF_SN_LIMIT)) != 0) {
REASON_SET(&ctx->reason, sn_reason);
goto csfailed;
}
@@ -6047,7 +6052,7 @@
if (r->rt) {
if ((r->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,
+ pd->af, &pd->act.rt_addr, pd->act.rt_kif, pd->act.rt_af,
PF_SN_ROUTE)) != 0) {
REASON_SET(&ctx->reason, sn_reason);
goto csfailed;
@@ -6066,7 +6071,7 @@
(sn_reason = pf_insert_src_node(sns, snhs, ctx->nr,
ctx->sk ? &(ctx->sk->addr[pd->sidx]) : pd->src, pd->af,
ctx->nk ? &(ctx->nk->addr[1]) : &(pd->nsaddr), NULL,
- PF_SN_NAT)) != 0 ) {
+ pd->naf, PF_SN_NAT)) != 0 ) {
REASON_SET(&ctx->reason, sn_reason);
goto csfailed;
}
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
@@ -2661,6 +2661,7 @@
PF_RULES_WUNLOCK();
goto out;
}
+ pa->af = pp->af;
switch (pp->which) {
case PF_NAT:
TAILQ_INSERT_TAIL(&V_pf_pabuf[0], pa, entries);
@@ -2742,6 +2743,7 @@
return (EBUSY);
}
pf_kpooladdr_to_pooladdr(pa, &pp->addr);
+ pp->af = pa->af;
pf_addr_copyout(&pp->addr.addr);
PF_RULES_RUNLOCK();
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
@@ -345,8 +345,8 @@
}
}
- if (pf_map_addr_sn(pd->naf, r, &pd->nsaddr, naddr, NULL, &init_addr,
- rpool, sn_type))
+ if (pf_map_addr_sn(pd->naf, r, &pd->nsaddr, naddr, &(pd->naf), NULL,
+ &init_addr, rpool, sn_type))
goto failed;
if (pd->proto == IPPROTO_ICMP) {
@@ -470,8 +470,8 @@
* pick a different source address since we're out
* of free port choices for the current one.
*/
- if (pf_map_addr_sn(pd->naf, r, &pd->nsaddr, naddr, NULL,
- &init_addr, rpool, sn_type))
+ if (pf_map_addr_sn(pd->naf, r, &pd->nsaddr, naddr,
+ &(pd->naf), NULL, &init_addr, rpool, sn_type))
return (1);
break;
case PF_POOL_NONE:
@@ -501,8 +501,8 @@
static int
pf_get_mape_sport(struct pf_pdesc *pd, struct pf_krule *r,
- struct pf_addr *naddr, uint16_t *nport,
- struct pf_udp_mapping **udp_mapping, struct pf_kpool *rpool)
+ struct pf_addr *naddr, uint16_t *nport, struct pf_udp_mapping **udp_mapping,
+ struct pf_kpool *rpool)
{
uint16_t psmask, low, highmask;
uint16_t i, ahigh, cut;
@@ -535,15 +535,22 @@
}
u_short
-pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr,
- struct pf_addr *naddr, struct pfi_kkif **nkif, struct pf_addr *init_addr,
- struct pf_kpool *rpool)
+pf_map_addr(sa_family_t saf, struct pf_krule *r, struct pf_addr *saddr,
+ struct pf_addr *naddr, struct pfi_kkif **nkif, sa_family_t *naf,
+ struct pf_addr *init_addr, struct pf_kpool *rpool)
{
u_short reason = PFRES_MATCH;
struct pf_addr *raddr = NULL, *rmask = NULL;
struct pfr_ktable *kt;
uint64_t hashidx;
int cnt;
+ sa_family_t wanted_af;
+
+ KASSERT(saf != 0, ("%s: saf == 0", __func__));
+ KASSERT(naf != NULL, ("%s: naf = NULL", __func__));
+ KASSERT((*naf) != 0, ("%s: *naf = 0", __func__));
+
+ wanted_af = (*naf);
mtx_lock(&rpool->mtx);
/* Find the route using chosen algorithm. Store the found route
@@ -553,7 +560,7 @@
goto done_pool_mtx;
}
if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
- switch (af) {
+ switch (wanted_af) {
#ifdef INET
case AF_INET:
if (rpool->cur->addr.p.dyn->pfid_acnt4 < 1 &&
@@ -577,7 +584,7 @@
break;
#endif /* INET6 */
default:
- unhandled_af(af);
+ unhandled_af(wanted_af);
}
} else if (rpool->cur->addr.type == PF_ADDR_TABLE) {
if (!PF_POOL_DYNTYPE(rpool->opts)) {
@@ -587,14 +594,24 @@
} else {
raddr = &rpool->cur->addr.v.a.addr;
rmask = &rpool->cur->addr.v.a.mask;
+ /*
+ * For single addresses check their address family. Unless they
+ * have none, which happens when addresses are added with
+ * the old ioctl mechanism. In such case trust that the address
+ * has the proper AF.
+ */
+ if (rpool->cur->af && rpool->cur->af != wanted_af) {
+ reason = PFRES_MAPFAILED;
+ goto done_pool_mtx;
+ }
}
switch (rpool->opts & PF_POOL_TYPEMASK) {
case PF_POOL_NONE:
- pf_addrcpy(naddr, raddr, af);
+ pf_addrcpy(naddr, raddr, wanted_af);
break;
case PF_POOL_BITMASK:
- pf_poolmask(naddr, raddr, rmask, saddr, af);
+ pf_poolmask(naddr, raddr, rmask, saddr, wanted_af);
break;
case PF_POOL_RANDOM:
if (rpool->cur->addr.type == PF_ADDR_TABLE ||
@@ -615,13 +632,14 @@
rpool->tblidx = (int)arc4random_uniform(cnt);
memset(&rpool->counter, 0, sizeof(rpool->counter));
if (pfr_pool_get(kt, &rpool->tblidx, &rpool->counter,
- af, pf_islinklocal, false)) {
+ wanted_af, pf_islinklocal, false)) {
reason = PFRES_MAPFAILED;
goto done_pool_mtx; /* unsupported */
}
- pf_addrcpy(naddr, &rpool->counter, af);
- } else if (init_addr != NULL && PF_AZERO(init_addr, af)) {
- switch (af) {
+ pf_addrcpy(naddr, &rpool->counter, wanted_af);
+ } else if (init_addr != NULL && PF_AZERO(init_addr,
+ wanted_af)) {
+ switch (wanted_af) {
#ifdef INET
case AF_INET:
rpool->counter.addr32[0] = arc4random();
@@ -650,12 +668,14 @@
break;
#endif /* INET6 */
}
- pf_poolmask(naddr, raddr, rmask, &rpool->counter, af);
- pf_addrcpy(init_addr, naddr, af);
+ pf_poolmask(naddr, raddr, rmask, &rpool->counter,
+ wanted_af);
+ pf_addrcpy(init_addr, naddr, wanted_af);
} else {
- pf_addr_inc(&rpool->counter, af);
- pf_poolmask(naddr, raddr, rmask, &rpool->counter, af);
+ pf_addr_inc(&rpool->counter, wanted_af);
+ pf_poolmask(naddr, raddr, rmask, &rpool->counter,
+ wanted_af);
}
break;
case PF_POOL_SRCHASH:
@@ -663,7 +683,8 @@
unsigned char hash[16];
hashidx =
- pf_hash(saddr, (struct pf_addr *)&hash, &rpool->key, af);
+ pf_hash(saddr, (struct pf_addr *)&hash, &rpool->key,
+ wanted_af);
if (rpool->cur->addr.type == PF_ADDR_TABLE ||
rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
if (rpool->cur->addr.type == PF_ADDR_TABLE)
@@ -682,14 +703,14 @@
rpool->tblidx = (int)(hashidx % cnt);
memset(&rpool->counter, 0, sizeof(rpool->counter));
if (pfr_pool_get(kt, &rpool->tblidx, &rpool->counter,
- af, pf_islinklocal, false)) {
+ wanted_af, pf_islinklocal, false)) {
reason = PFRES_MAPFAILED;
goto done_pool_mtx; /* unsupported */
}
- pf_addrcpy(naddr, &rpool->counter, af);
+ pf_addrcpy(naddr, &rpool->counter, wanted_af);
} else {
pf_poolmask(naddr, raddr, rmask,
- (struct pf_addr *)&hash, af);
+ (struct pf_addr *)&hash, wanted_af);
}
break;
}
@@ -699,14 +720,16 @@
if (rpool->cur->addr.type == PF_ADDR_TABLE) {
if (!pfr_pool_get(rpool->cur->addr.p.tbl,
- &rpool->tblidx, &rpool->counter, af, NULL, true))
+ &rpool->tblidx, &rpool->counter, wanted_af,
+ NULL, true))
goto get_addr;
} else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
if (!pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt,
- &rpool->tblidx, &rpool->counter, af, pf_islinklocal,
- true))
+ &rpool->tblidx, &rpool->counter, wanted_af,
+ pf_islinklocal, true))
goto get_addr;
- } else if (pf_match_addr(0, raddr, rmask, &rpool->counter, af))
+ } else if (pf_match_addr(0, raddr, rmask, &rpool->counter,
+ wanted_af))
goto get_addr;
try_next:
@@ -717,8 +740,9 @@
rpool->tblidx = -1;
if (rpool->cur->addr.type == PF_ADDR_TABLE) {
if (pfr_pool_get(rpool->cur->addr.p.tbl,
- &rpool->tblidx, &rpool->counter, af, NULL, true)) {
- /* table contains no address of type 'af' */
+ &rpool->tblidx, &rpool->counter, wanted_af, NULL,
+ true)) {
+ /* table contains no address of type 'wanted_af' */
if (rpool->cur != acur)
goto try_next;
reason = PFRES_MAPFAILED;
@@ -726,9 +750,9 @@
}
} else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
if (pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt,
- &rpool->tblidx, &rpool->counter, af, pf_islinklocal,
- true)) {
- /* table contains no address of type 'af' */
+ &rpool->tblidx, &rpool->counter, wanted_af,
+ pf_islinklocal, true)) {
+ /* interface has no address of type 'wanted_af' */
if (rpool->cur != acur)
goto try_next;
reason = PFRES_MAPFAILED;
@@ -737,14 +761,18 @@
} else {
raddr = &rpool->cur->addr.v.a.addr;
rmask = &rpool->cur->addr.v.a.mask;
- pf_addrcpy(&rpool->counter, raddr, af);
+ if (rpool->cur->af && rpool->cur->af != wanted_af) {
+ reason = PFRES_MAPFAILED;
+ goto done_pool_mtx;
+ }
+ pf_addrcpy(&rpool->counter, raddr, wanted_af);
}
get_addr:
- pf_addrcpy(naddr, &rpool->counter, af);
- if (init_addr != NULL && PF_AZERO(init_addr, af))
- pf_addrcpy(init_addr, naddr, af);
- pf_addr_inc(&rpool->counter, af);
+ pf_addrcpy(naddr, &rpool->counter, wanted_af);
+ if (init_addr != NULL && PF_AZERO(init_addr, wanted_af))
+ pf_addrcpy(init_addr, naddr, wanted_af);
+ pf_addr_inc(&rpool->counter, wanted_af);
break;
}
}
@@ -759,9 +787,9 @@
}
u_short
-pf_map_addr_sn(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr,
- struct pf_addr *naddr, struct pfi_kkif **nkif, struct pf_addr *init_addr,
- struct pf_kpool *rpool, pf_sn_types_t sn_type)
+pf_map_addr_sn(sa_family_t saf, struct pf_krule *r, struct pf_addr *saddr,
+ struct pf_addr *naddr, sa_family_t *naf, struct pfi_kkif **nkif,
+ struct pf_addr *init_addr, struct pf_kpool *rpool, pf_sn_types_t sn_type)
{
struct pf_ksrc_node *sn = NULL;
struct pf_srchash *sh = NULL;
@@ -772,27 +800,31 @@
*/
if (rpool->opts & PF_POOL_STICKYADDR &&
(rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE)
- sn = pf_find_src_node(saddr, r, af, &sh, sn_type, false);
+ sn = pf_find_src_node(saddr, r, saf, &sh, sn_type, false);
if (sn != NULL) {
PF_SRC_NODE_LOCK_ASSERT(sn);
+ (*naf) = sn->raf;
/* If the supplied address is the same as the current one we've
* been asked before, so tell the caller that there's no other
* address to be had. */
- if (PF_AEQ(naddr, &(sn->raddr), af)) {
+
+ if (PF_AEQ(naddr, &(sn->raddr), *naf)) {
+ printf("%s: no more addresses\n", __func__);
reason = PFRES_MAPFAILED;
goto done;
}
- pf_addrcpy(naddr, &(sn->raddr), af);
+ pf_addrcpy(naddr, &(sn->raddr), *naf);
+
if (nkif)
*nkif = sn->rkif;
if (V_pf_status.debug >= PF_DEBUG_NOISY) {
printf("%s: src tracking maps ", __func__);
- pf_print_host(saddr, 0, af);
+ pf_print_host(saddr, 0, saf);
printf(" to ");
- pf_print_host(naddr, 0, af);
+ pf_print_host(naddr, 0, *naf);
if (nkif)
printf("@%s", (*nkif)->pfik_name);
printf("\n");
@@ -804,7 +836,7 @@
* Source node has not been found. Find a new address and store it
* in variables given by the caller.
*/
- if ((reason = pf_map_addr(af, r, saddr, naddr, nkif, init_addr,
+ if ((reason = pf_map_addr(saf, r, saddr, naddr, nkif, naf, init_addr,
rpool)) != 0) {
if (V_pf_status.debug >= PF_DEBUG_MISC)
printf("%s: pf_map_addr has failed\n", __func__);
@@ -814,7 +846,7 @@
if (V_pf_status.debug >= PF_DEBUG_NOISY &&
(rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
printf("%s: selected address ", __func__);
- pf_print_host(naddr, 0, af);
+ pf_print_host(naddr, 0, *naf);
if (nkif)
printf("@%s", (*nkif)->pfik_name);
printf("\n");
@@ -996,8 +1028,9 @@
int tries;
uint16_t cut, low, high, nport;
- reason = pf_map_addr_sn(pd->af, r, &pd->nsaddr, naddr, NULL,
- NULL, rpool, PF_SN_NAT);
+ reason = pf_map_addr_sn(pd->af, r, &pd->nsaddr, naddr,
+ &(pd->naf), NULL, NULL, rpool, PF_SN_NAT);
+
if (reason != 0)
goto notrans;
if ((rpool->opts & PF_POOL_TYPEMASK) == PF_POOL_BITMASK)
@@ -1161,8 +1194,8 @@
/* get the destination address and port */
if (! TAILQ_EMPTY(&r->rdr.list)) {
- if (pf_map_addr_sn(pd->naf, r, &nsaddr, &naddr, NULL, NULL,
- &r->rdr, PF_SN_NAT))
+ if (pf_map_addr_sn(pd->naf, r, &nsaddr, &naddr, &(pd->naf),
+ NULL, NULL, &r->rdr, PF_SN_NAT))
return (-1);
if (r->rdr.proxy_port[0])
pd->ndport = htons(r->rdr.proxy_port[0]);
diff --git a/sys/netpfil/pf/pf_nl.h b/sys/netpfil/pf/pf_nl.h
--- a/sys/netpfil/pf/pf_nl.h
+++ b/sys/netpfil/pf/pf_nl.h
@@ -135,6 +135,7 @@
PF_ST_RT = 36, /* u8 */
PF_ST_RT_IFNAME = 37, /* string */
PF_ST_SRC_NODE_FLAGS = 38, /* u8 */
+ PF_ST_RT_AF = 39, /* u8 */
};
enum pf_addr_type_t {
@@ -433,7 +434,7 @@
PF_SN_CREATION = 12, /* u64 */
PF_SN_EXPIRE = 13, /* u64 */
PF_SN_CONNECTION_RATE = 14, /* nested, pf_threshold */
- PF_SN_NAF = 15, /* u8 */
+ PF_SN_RAF = 15, /* u8 */
PF_SN_NODE_TYPE = 16, /* u8 */
};
diff --git a/sys/netpfil/pf/pf_nl.c b/sys/netpfil/pf/pf_nl.c
--- a/sys/netpfil/pf/pf_nl.c
+++ b/sys/netpfil/pf/pf_nl.c
@@ -178,7 +178,7 @@
nlattr_add_string(nw, PF_ST_IFNAME, s->kif->pfik_name);
nlattr_add_string(nw, PF_ST_ORIG_IFNAME, s->orig_kif->pfik_name);
- dump_addr(nw, PF_ST_RT_ADDR, &s->act.rt_addr, af);
+ dump_addr(nw, PF_ST_RT_ADDR, &s->act.rt_addr, s->act.rt_af);
nlattr_add_u32(nw, PF_ST_CREATION, time_uptime - (s->creation / 1000));
uint32_t expire = pf_state_expires(s);
if (expire > time_uptime)
@@ -224,6 +224,7 @@
if (s->sns[PF_SN_ROUTE] != NULL)
src_node_flags |= PFSTATE_SRC_NODE_ROUTE;
nlattr_add_u8(nw, PF_ST_SRC_NODE_FLAGS, src_node_flags);
+ nlattr_add_u8(nw, PF_ST_RT_AF, s->act.rt_af);
if (!dump_state_peer(nw, PF_ST_PEER_SRC, &s->src))
goto enomem;
@@ -1761,7 +1762,7 @@
nlattr_add_u32(nw, PF_SN_STATES, n->states);
nlattr_add_u32(nw, PF_SN_CONNECTIONS, n->conn);
nlattr_add_u8(nw, PF_SN_AF, n->af);
- nlattr_add_u8(nw, PF_SN_NAF, n->naf);
+ nlattr_add_u8(nw, PF_SN_RAF, n->raf);
nlattr_add_u8(nw, PF_SN_RULE_TYPE, n->ruletype);
nlattr_add_u64(nw, PF_SN_CREATION, secs - n->creation);
diff --git a/tests/sys/netpfil/pf/nat64.sh b/tests/sys/netpfil/pf/nat64.sh
--- a/tests/sys/netpfil/pf/nat64.sh
+++ b/tests/sys/netpfil/pf/nat64.sh
@@ -916,6 +916,15 @@
atf_check -s exit:0 -o ignore \
ping6 -c 3 64:ff9b::192.0.2.2
+
+ states=$(mktemp) || exit 1
+ jexec rtr pfctl -qvvss | normalize_pfctl_s > $states
+
+ for state_regexp in \
+ "${epair}b ipv6-icmp 192.0.2.1:.* \(2001:db8::2\[[0-9]+\]\) -> 192.0.2.2:8 \(64:ff9b::c000:202\[[0-9]+\]\).*4:2 pkts.*route-to: 192.0.2.2@${epair_link}a" \
+ ; do
+ grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'"
+ done
}
route_to_cleanup()
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
@@ -503,6 +503,66 @@
pft_cleanup
}
+atf_test_case "mixed_af" "cleanup"
+mixed_af_head()
+{
+ atf_set descr 'Test mixed address family source tracking'
+ atf_set require.user root
+}
+
+mixed_af_body()
+{
+ setup_router_server_nat64
+
+ # Clients will connect from another network behind the router.
+ # This allows for using multiple source addresses.
+ jexec router route add -6 ${net_clients_6}::/${net_clients_6_mask} ${net_tester_6_host_tester}
+
+ jexec router pfctl -e
+ pft_set_rules router \
+ "set reassemble yes" \
+ "set state-policy if-bound" \
+ "pass in on ${epair_tester}b \
+ route-to { (${epair_server1}a ${net_server1_4_host_server}) \
+ } sticky-address \
+ inet6 proto tcp from any to 64:ff9b::/96 \
+ af-to inet from ${net_clients_4}.0/${net_clients_4_mask} round-robin sticky-address"
+
+ atf_check -s exit:0 ${common_dir}/pft_ping.py \
+ --sendif ${epair_tester}a \
+ --replyif ${epair_tester}a \
+ --fromaddr 2001:db8:44::1 \
+ --to 64:ff9b::192.0.2.100 \
+ --ping-type=tcp3way \
+ --send-sport=4201
+
+ states=$(mktemp) || exit 1
+ jexec router pfctl -qvvss | normalize_pfctl_s > $states
+ nodes=$(mktemp) || exit 1
+ jexec router pfctl -qvvsS | normalize_pfctl_s > $nodes
+
+ # States are checked for proper route-to information.
+ # The route-to gateway is IPv4.
+ for state_regexp in \
+ "${epair_tester}b tcp 203.0.113.0:4201 \(2001:db8:44::1\[4201\]\) -> 192.0.2.100:9 \(64:ff9b::c000:264\[9\]\) .* route-to: 198.51.100.18@${epair_server1}a" \
+ ; do
+ grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'"
+ done
+
+ # Source nodes map IPv6 source address onto IPv4 gateway and IPv4 SNAT address.
+ for node_regexp in \
+ '2001:db8:44::1 -> 203.0.113.0 .* states 1, .* NAT/RDR sticky-address' \
+ '2001:db8:44::1 -> 198.51.100.18 .* states 1, .* route sticky-address' \
+ ; do
+ grep -qE "${node_regexp}" $nodes || atf_fail "Source node not found for '${node_regexp}'"
+ done
+}
+
+mixed_af_cleanup()
+{
+ pft_cleanup
+}
+
atf_init_test_cases()
{
atf_add_test_case "source_track"
@@ -512,4 +572,5 @@
atf_add_test_case "max_src_states_global"
atf_add_test_case "sn_types_compat"
atf_add_test_case "sn_types_pass"
+ atf_add_test_case "mixed_af"
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Dec 12, 4:00 PM (8 h, 25 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
26901687
Default Alt Text
D51659.diff (32 KB)
Attached To
Mode
D51659: pf: Use different address family for source and redirection address
Attached
Detach File
Event Timeline
Log In to Comment