Hi,
"route-to" is used with the interface used for the next hop. But if
it is used with a source address track (sticky-address), it sometimes
output the packet to wrong interface.
Example:
pass in quick inet proto tcp from any to 192.168.0.10 port 80 \
keep state (sloppy) route-to <LB> source-hash hogehoge sticky-address
# pfctl -Tshow -tLB
127.0.0.1@lo0
192.168.0.101@em0
192.168.0.102@em0
#
pf_test() => pf_route() uses r->route->kif as the output inteface.
If there is no active source address tracking record, r->route->kif is
properly set with the table entry at pfr_pool_get() (called from
pf_map_addr() <= pf_route() <= pf_route()). But there is an active
source tracking record, pf_map_addr() returns without updating
r->route->kif.
339 int
340 pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
341 struct pf_addr *naddr, struct pf_addr *init_addr, struct
pf_src_node **sns,
342 struct pf_pool *rpool, enum pf_sn_types type)
343 {
(snip)
355 if (sns[type] == NULL && rpool->opts & PF_POOL_STICKYADDR &&
356 (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE &&
357 pf_map_addr_sticky(af, r, saddr, naddr, sns, rpool, type)
== 0)
358 return (0);
Since pf_map_sticky() doesn't update the kif, kif used previous is
used mistakenly.
ok?
When source address tracking record is used for "route-to", the next
hop interface configured with "route-to" was not used. Keep the
interface within the pf_src_node and use it when the record is used.
Index: sys/net/pf.c
===================================================================
RCS file: /cvs/src/sys/net/pf.c,v
retrieving revision 1.1081
diff -u -p -r1.1081 pf.c
--- sys/net/pf.c 20 Mar 2019 20:07:28 -0000 1.1081
+++ sys/net/pf.c 1 Jul 2019 11:47:36 -0000
@@ -542,7 +542,7 @@ pf_src_connlimit(struct pf_state **state
int
pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule,
enum pf_sn_types type, sa_family_t af, struct pf_addr *src,
- struct pf_addr *raddr)
+ struct pf_addr *raddr, struct pfi_kif *kif)
{
struct pf_src_node k;
@@ -586,6 +586,7 @@ pf_insert_src_node(struct pf_src_node **
}
(*sn)->creation = time_uptime;
(*sn)->rule.ptr->src_nodes++;
+ (*sn)->kif = kif;
pf_status.scounters[SCNT_SRC_NODE_INSERT]++;
pf_status.src_nodes++;
} else {
@@ -3882,7 +3883,7 @@ pf_test_rule(struct pf_pdesc *pd, struct
if (r->rule_flag & PFRULE_SRCTRACK &&
pf_insert_src_node(&ctx.sns[PF_SN_NONE], r, PF_SN_NONE,
- pd->af, pd->src, NULL) != 0) {
+ pd->af, pd->src, NULL, NULL) != 0) {
REASON_SET(&ctx.reason, PFRES_SRCLIMIT);
goto cleanup;
}
Index: sys/net/pf_lb.c
===================================================================
RCS file: /cvs/src/sys/net/pf_lb.c,v
retrieving revision 1.63
diff -u -p -r1.63 pf_lb.c
--- sys/net/pf_lb.c 10 Dec 2018 16:48:15 -0000 1.63
+++ sys/net/pf_lb.c 1 Jul 2019 11:47:36 -0000
@@ -329,6 +329,10 @@ pf_map_addr_sticky(sa_family_t af, struc
pf_print_host(naddr, 0, af);
addlog("\n");
}
+
+ if (sns[type]->kif != NULL)
+ rpool->kif = sns[type]->kif;
+
return (0);
}
@@ -618,7 +622,8 @@ pf_map_addr(sa_family_t af, struct pf_ru
pf_remove_src_node(sns[type]);
sns[type] = NULL;
}
- if (pf_insert_src_node(&sns[type], r, type, af, saddr, naddr))
+ if (pf_insert_src_node(&sns[type], r, type, af, saddr, naddr,
+ rpool->kif))
return (1);
}
Index: sys/net/pfvar.h
===================================================================
RCS file: /cvs/src/sys/net/pfvar.h,v
retrieving revision 1.490
diff -u -p -r1.490 pfvar.h
--- sys/net/pfvar.h 18 Feb 2019 13:11:44 -0000 1.490
+++ sys/net/pfvar.h 1 Jul 2019 11:47:36 -0000
@@ -1712,7 +1712,7 @@ extern int pf_state_insert(struct
pfi
int pf_insert_src_node(struct pf_src_node **,
struct pf_rule *, enum pf_sn_types,
sa_family_t, struct pf_addr *,
- struct pf_addr *);
+ struct pf_addr *, struct pfi_kif *);
void pf_remove_src_node(struct pf_src_node *);
struct pf_src_node *pf_get_src_node(struct pf_state *,
enum pf_sn_types);