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

Reply via email to