Hi All
I'm testing this patch to permit synchronization of states that use
route-to or reply-to for policy routing, this patch apply to OpenBSD
v4.6 -stable, this is the problem:
when pfsync send an state that uses route-to or reply-to option to the
other machine, it only sends only current next-hop address in rt_addr
member of pfsync_state struct, the peer gets the pfsync data and it
will try to insert the state and bind it to ruleset, when the
secondary machine gets active and a packet going to pass through pf
will try to process pf_route if the state matches with a rule with
route/reply option, but the interface information hadn't inserted into
the state so the state will has st->rt_kif = NULL then the packet will
be droped in pf_route function.
To complete the route/reply option of one state and keep compatibility
with pfsync_state structure, we can use the data space holding by pad
member into pfsync_state_peer, it seems to not be used by other
function, so we can free rename, I rename it as ex_info (extra info),
so we can use it to put the info to complete the state. The ex_info
data is 6 bytes length so we can't put the st->rt_kif->pfik_name data
here. We can put the relative position of the rt_kif into the
route/reply pool, this manner we need only 2 bytes to send the integer
that represents the relative position into the pool, so when a peer
receives the pfsync data it can bind it into the pool if the both
ruleset have a checksum match.
I made some tests and it is running fine, this patch can be ported to
the -current version of cvs, but we need to make a little changes
beacuse rpool member of pf_rule struct has a new name: route.
The modified functions was: pfsync_state_export, pfsync_state_import
and pfsync_in_upd, the pfsync_in_upd was inserted a new state with
flags equal to zero, now it insert the new state with the pkt->flags,
so if the ruleset checksum matches this state will be attached to the
ruleset in pfsync_state_import function
===================================================================
RCS file: src/sys/net/RCS/if_pfsync.c,v
retrieving revision 1.127
diff -u -r1.127 src/sys/net/if_pfsync.c
--- src/sys/net/if_pfsync.c 2010/01/13 23:06:38 1.127
+++ src/sys/net/if_pfsync.c 2010/01/14 21:45:18
@@ -398,6 +398,9 @@
void
pfsync_state_export(struct pfsync_state *sp, struct pf_state *st)
{
+ struct pf_pooladdr *acur = NULL;
+ struct pf_rule *r = NULL;
+ int count = 0;
bzero(sp, sizeof(struct pfsync_state));
/* copy from state key */
@@ -449,6 +452,20 @@
else
sp->nat_rule = htonl(st->nat_rule.ptr->nr);
+ /* insert the rpool position reference for route-to states */
+ if(st->rt_kif) {
+ if(sp->rule != htonl(-1) && ntohl(sp->rule) <
pf_main_ruleset.rules[PF_RULESET_FILTER].active.rcount)
+ r =
pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr_array[ntohl(sp->rule)];
+ if(r != NULL) {
+ TAILQ_FOREACH(acur, &r->rpool.list, entries) {
+ count++;
+ if(st->rt_kif == acur->kif)
+ break;
+ }
+ }
+ bcopy(&count, &sp->dst.ex_info, sizeof(count));
+ }
+
pf_state_counter_hton(st->packets[0], sp->packets[0]);
pf_state_counter_hton(st->packets[1], sp->packets[1]);
pf_state_counter_hton(st->bytes[0], sp->bytes[0]);
@@ -465,6 +482,9 @@
struct pfi_kif *kif;
int pool_flags;
int error;
+ struct pf_pooladdr *acur;
+ int count;
+ int i;
if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) {
printf("pfsync_state_import: invalid creator id:"
@@ -563,6 +583,19 @@
st->nat_rule.ptr = NULL;
st->anchor.ptr = NULL;
st->rt_kif = NULL;
+ /* try to insert the route-to kif for this state */
+ if(r != &pf_default_rule && r->rpool.cur) {
+ bcopy(&sp->dst.ex_info, &count, sizeof(count));
+ i = 0;
+ TAILQ_FOREACH(acur, &r->rpool.list, entries) {
+ i++;
+ if(i == count) {
+ st->rt_kif = acur->kif;
+ break;
+ }
+ }
+ }
+
st->pfsync_time = time_uptime;
st->sync_state = PFSYNC_S_NONE;
@@ -916,7 +949,7 @@
st = pf_find_state_byid(&id_key);
if (st == NULL) {
/* insert the update */
- if (pfsync_state_import(sp, 0))
+ if (pfsync_state_import(sp, pkt->flags))
pfsyncstats.pfsyncs_badstate++;
continue;
}
===================================================================
RCS file: src/sys/net/RCS/pfvar.h,v
retrieving revision 1.290
diff -u -r1.290 src/sys/net/pfvar.h
--- src/sys/net/pfvar.h 2010/01/13 23:33:23 1.290
+++ src/sys/net/pfvar.h 2010/01/14 19:38:00
@@ -826,7 +826,7 @@
u_int16_t mss; /* Maximum segment size option */
u_int8_t state; /* active state level */
u_int8_t wscale; /* window scaling factor */
- u_int8_t pad[6];
+ u_int8_t ex_info[6];
} __packed;
struct pfsync_state_key {
I sent the other patch before, this patch add a new member to
pfsync_state to hold the ifname of the interface in route/reply-to
state, but to use this patch you will need to recompile some dependent
pfvar.h applications (like pfctl) to use the new data structure, this
patch is used in OpenBSD v4.6 -stable too:
===================================================================
RCS file: src/sys/net/RCS/if_pfsync.c,v
retrieving revision 1.127
diff -u -r1.127 src/sys/net/if_pfsync.c
--- src/sys/net/if_pfsync.c 2010/01/13 23:06:38 1.127
+++ src/sys/net/if_pfsync.c 2010/01/14 01:14:22
@@ -415,6 +415,9 @@
/* copy from state */
strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname));
bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
+ /* if state has route-to option, export rt interface name too*/
+ if(st->rt_kif)
+ strlcpy(sp->rt_ifname, st->rt_kif->pfik_name,
sizeof(sp->rt_ifname));
sp->creation = htonl(time_second - st->creation);
sp->expire = pf_state_expires(st);
if (sp->expire <= time_second)
@@ -562,7 +565,12 @@
st->rule.ptr = r;
st->nat_rule.ptr = NULL;
st->anchor.ptr = NULL;
- st->rt_kif = NULL;
+ /* if the state had mached with ruleset we can bind the
+ interface for route-to, reply-to rules */
+ if(r != &pf_default_rule && r->rpool.cur)
+ st->rt_kif = pfi_kif_get(sp->rt_ifname);
+ else
+ st->rt_kif = NULL;
st->pfsync_time = time_uptime;
st->sync_state = PFSYNC_S_NONE;
@@ -916,7 +924,7 @@
st = pf_find_state_byid(&id_key);
if (st == NULL) {
/* insert the update */
- if (pfsync_state_import(sp, 0))
+ if (pfsync_state_import(sp, pkt->flags))
pfsyncstats.pfsyncs_badstate++;
continue;
}
===================================================================
RCS file: src/sys/net/RCS/pfvar.h,v
retrieving revision 1.290
diff -u -r1.290 src/sys/net/pfvar.h
--- src/sys/net/pfvar.h 2010/01/14 01:04:54 1.290
+++ src/sys/net/pfvar.h 2010/01/14 01:08:05
@@ -841,6 +841,7 @@
struct pfsync_state_peer src;
struct pfsync_state_peer dst;
struct pf_addr rt_addr;
+ char rt_ifname[IFNAMSIZ];
u_int32_t rule;
u_int32_t anchor;
u_int32_t nat_rule;
I hope this can help for some one, please let me know if anybody have
another idea to sync route-to, reply-to states.
- Romey