On 22.8.2012. 20:50, Florian Obser wrote:
> Hi,
>
> I think I got this now.
> - replace time_seconds with time_uptime
> - with that flow_finish in pflow can be simplified (pointed out by benno@)
> this should take care of flows with finish < start for localy created
> states
> - change various variables from unsigned to signed (mainly) in pfsync which
> could underflow (inspired by a patch from dlg@ from last year, pointed out
> by cameild@). This fixes pflow and at the same time an underflow problem
> in pfsync which dlg's patch was addressing. If I understand the history
> correctly cameild@ noticed this problem last year.
>
> Hrvoje Popovski tested an older version without the pfsync fix.
>
> Since this changes the semantics of a field in pfsync both pfsync machines
> need to be updated (I think it's ok to import 5.1 states into this version
> but the other way around will cause problems.)
>
> We are running with this patch since yesterday on a redundant firewall
> (amd64) with pfsync and no longer see broken flows (i.e. where finish
> < start). The pair survived various failovers.
>
> Index: share/man/man4/pflow.4
> ===================================================================
> RCS file: /opt/OpenBSD-CVS/src/share/man/man4/pflow.4,v
> retrieving revision 1.11
> diff -u -p -u -r1.11 pflow.4
> --- share/man/man4/pflow.4 2 Feb 2012 12:34:37 -0000 1.11
> +++ share/man/man4/pflow.4 22 Aug 2012 18:20:08 -0000
> @@ -127,6 +127,12 @@ The
> device first appeared in
> .Ox 4.5 .
> .Sh BUGS
> +A state created by
> +.Xr pfsync 4
> +can have a creation or expiration time before the machine came up.
> +.Nm
> +pretends the flow was created or expired when the machine came up.
> +
> The IPFIX implementation is incomplete:
> The required transport protocol SCTP is not supported.
> Transport over TCP and DTLS protected flow export is also not supported.
> Index: sys/net/if_pflow.c
> ===================================================================
> RCS file: /opt/OpenBSD-CVS/src/sys/net/if_pflow.c,v
> retrieving revision 1.20
> diff -u -p -u -r1.20 if_pflow.c
> --- sys/net/if_pflow.c 11 Apr 2012 17:42:53 -0000 1.20
> +++ sys/net/if_pflow.c 22 Aug 2012 18:20:08 -0000
> @@ -553,12 +553,15 @@ copy_flow_data(struct pflow_flow *flow1,
> flow1->flow_octets = htonl(st->bytes[0]);
> flow2->flow_octets = htonl(st->bytes[1]);
>
> - flow1->flow_start = flow2->flow_start =
> + /*
> + * Pretend the flow was created or expired when this machine
> + * came up when the state's creation or expiration is in the past.
> + */
> + flow1->flow_start = flow2->flow_start = st->creation < 0 ? 0 :
> htonl(st->creation * 1000);
> - flow1->flow_finish = flow2->flow_finish =
> - htonl((time_uptime - (st->rule.ptr->timeout[st->timeout] ?
> - st->rule.ptr->timeout[st->timeout] :
> - pf_default_rule.timeout[st->timeout])) * 1000);
> + flow1->flow_finish = flow2->flow_finish = st->expire < 0 ? 0 :
> + htonl(st->expire * 1000);
> +
> flow1->tcp_flags = flow2->tcp_flags = 0;
> flow1->protocol = flow2->protocol = sk->proto;
> flow1->tos = flow2->tos = st->rule.ptr->tos;
> @@ -580,12 +583,14 @@ copy_flow4_data(struct pflow_flow4 *flow
> flow1->flow_octets = htobe64(st->bytes[0]);
> flow2->flow_octets = htobe64(st->bytes[1]);
>
> - flow1->flow_start = flow2->flow_start =
> + /*
> + * Pretend the flow was created or expired when this machine
> + * came up when the state's creation or expiration is in the past.
> + */
> + flow1->flow_start = flow2->flow_start = st->creation < 0 ? 0 :
> htonl(st->creation * 1000);
> - flow1->flow_finish = flow2->flow_finish =
> - htonl((time_uptime - (st->rule.ptr->timeout[st->timeout] ?
> - st->rule.ptr->timeout[st->timeout] :
> - pf_default_rule.timeout[st->timeout])) * 1000);
> + flow1->flow_finish = flow2->flow_finish = st->expire < 0 ? 0 :
> + htonl(st->expire * 1000);
>
> flow1->protocol = flow2->protocol = sk->proto;
> flow1->tos = flow2->tos = st->rule.ptr->tos;
> @@ -608,12 +613,14 @@ copy_flow6_data(struct pflow_flow6 *flow
> flow1->flow_octets = htobe64(st->bytes[0]);
> flow2->flow_octets = htobe64(st->bytes[1]);
>
> - flow1->flow_start = flow2->flow_start =
> + /*
> + * Pretend the flow was created or expired when this machine
> + * came up when the state's creation or expiration is in the past.
> + */
> + flow1->flow_start = flow2->flow_start = st->creation < 0 ? 0 :
> htonl(st->creation * 1000);
> - flow1->flow_finish = flow2->flow_finish =
> - htonl((time_uptime - (st->rule.ptr->timeout[st->timeout] ?
> - st->rule.ptr->timeout[st->timeout] :
> - pf_default_rule.timeout[st->timeout])) * 1000);
> + flow1->flow_finish = flow2->flow_finish = st->expire < 0 ? 0 :
> + htonl(st->expire * 1000);
>
> flow1->protocol = flow2->protocol = sk->proto;
> flow1->tos = flow2->tos = st->rule.ptr->tos;
> Index: sys/net/if_pfsync.c
> ===================================================================
> RCS file: /opt/OpenBSD-CVS/src/sys/net/if_pfsync.c,v
> retrieving revision 1.189
> diff -u -p -u -r1.189 if_pfsync.c
> --- sys/net/if_pfsync.c 26 Jul 2012 12:25:31 -0000 1.189
> +++ sys/net/if_pfsync.c 22 Aug 2012 18:20:08 -0000
> @@ -464,6 +464,7 @@ void
> pfsync_state_export(struct pfsync_state *sp, struct pf_state *st)
> {
> pf_state_export(sp, st);
> + sp->expire = htonl(time_uptime - st->expire);
> }
>
> int
> @@ -574,17 +575,7 @@ pfsync_state_import(struct pfsync_state
> /* copy to state */
> bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr));
> st->creation = time_uptime - ntohl(sp->creation);
> - st->expire = time_second;
> - if (sp->expire) {
> - u_int32_t timeout;
> -
> - timeout = r->timeout[sp->timeout];
> - if (!timeout)
> - timeout = pf_default_rule.timeout[sp->timeout];
> -
> - /* sp->expire may have been adaptively scaled by export. */
> - st->expire -= timeout - ntohl(sp->expire);
> - }
> + st->expire = time_uptime - ntohl(sp->expire);
>
> st->direction = sp->direction;
> st->log = sp->log;
> @@ -948,7 +939,7 @@ pfsync_in_upd(caddr_t buf, int len, int
> if (sync < 2) {
> pfsync_alloc_scrub_memory(&sp->dst, &st->dst);
> pf_state_peer_ntoh(&sp->dst, &st->dst);
> - st->expire = time_second;
> + st->expire = time_uptime;
> st->timeout = sp->timeout;
> }
> st->pfsync_time = time_uptime;
> @@ -1022,7 +1013,7 @@ pfsync_in_upd_c(caddr_t buf, int len, in
> if (sync < 2) {
> pfsync_alloc_scrub_memory(&up->dst, &st->dst);
> pf_state_peer_ntoh(&up->dst, &st->dst);
> - st->expire = time_second;
> + st->expire = time_uptime;
> st->timeout = up->timeout;
> }
> st->pfsync_time = time_uptime;
> Index: sys/net/pf.c
> ===================================================================
> RCS file: /opt/OpenBSD-CVS/src/sys/net/pf.c,v
> retrieving revision 1.809
> diff -u -p -u -r1.809 pf.c
> --- sys/net/pf.c 26 Jul 2012 12:25:31 -0000 1.809
> +++ sys/net/pf.c 22 Aug 2012 18:20:08 -0000
> @@ -389,13 +389,13 @@ pf_init_threshold(struct pf_threshold *t
> threshold->limit = limit * PF_THRESHOLD_MULT;
> threshold->seconds = seconds;
> threshold->count = 0;
> - threshold->last = time_second;
> + threshold->last = time_uptime;
> }
>
> void
> pf_add_threshold(struct pf_threshold *threshold)
> {
> - u_int32_t t = time_second, diff = t - threshold->last;
> + u_int32_t t = time_uptime, diff = t - threshold->last;
>
> if (diff >= threshold->seconds)
> threshold->count = 0;
> @@ -582,7 +582,7 @@ pf_insert_src_node(struct pf_src_node **
> void
> pf_remove_src_node(struct pf_src_node *sn)
> {
> - if (sn->states > 0 || sn->expire > time_second)
> + if (sn->states > 0 || sn->expire > time_uptime)
> return;
>
> if (sn->rule.ptr != NULL) {
> @@ -1105,10 +1105,10 @@ pf_state_export(struct pfsync_state *sp,
> bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
> sp->creation = htonl(time_uptime - st->creation);
> sp->expire = pf_state_expires(st);
> - if (sp->expire <= time_second)
> + if (sp->expire <= time_uptime)
> sp->expire = htonl(0);
> else
> - sp->expire = htonl(sp->expire - time_second);
> + sp->expire = htonl(sp->expire - time_uptime);
>
> sp->direction = st->direction;
> sp->log = st->log;
> @@ -1169,7 +1169,7 @@ pf_purge_thread(void *v)
> }
> }
>
> -u_int32_t
> +int32_t
> pf_state_expires(const struct pf_state *state)
> {
> u_int32_t timeout;
> @@ -1179,7 +1179,7 @@ pf_state_expires(const struct pf_state *
>
> /* handle all PFTM_* > PFTM_MAX here */
> if (state->timeout == PFTM_PURGE)
> - return (time_second);
> + return (time_uptime);
> KASSERT(state->timeout != PFTM_UNLINKED);
> KASSERT(state->timeout < PFTM_MAX);
> timeout = state->rule.ptr->timeout[state->timeout];
> @@ -1199,7 +1199,7 @@ pf_state_expires(const struct pf_state *
> return (state->expire + timeout * (end - states) /
> (end - start));
> else
> - return (time_second);
> + return (time_uptime);
> }
> return (state->expire + timeout);
> }
> @@ -1213,7 +1213,7 @@ pf_purge_expired_src_nodes(int waslocked
> for (cur = RB_MIN(pf_src_tree, &tree_src_tracking); cur; cur = next) {
> next = RB_NEXT(pf_src_tree, &tree_src_tracking, cur);
>
> - if (cur->states <= 0 && cur->expire <= time_second) {
> + if (cur->states <= 0 && cur->expire <= time_uptime) {
> if (! locked) {
> rw_enter_write(&pf_consistency_lock);
> next = RB_NEXT(pf_src_tree,
> @@ -1243,7 +1243,7 @@ pf_src_tree_remove_state(struct pf_state
> if (!timeout)
> timeout =
> pf_default_rule.timeout[PFTM_SRC_NODE];
> - sni->sn->expire = time_second + timeout;
> + sni->sn->expire = time_uptime + timeout;
> }
> pool_put(&pf_sn_item_pl, sni);
> }
> @@ -1343,7 +1343,7 @@ pf_purge_expired_states(u_int32_t maxche
> locked = 1;
> }
> pf_free_state(cur);
> - } else if (pf_state_expires(cur) <= time_second) {
> + } else if (pf_state_expires(cur) <= time_uptime) {
> /* unlink and free expired state */
> pf_unlink_state(cur);
> if (! locked) {
> @@ -3761,7 +3761,7 @@ pf_create_state(struct pf_pdesc *pd, str
> }
>
> s->creation = time_uptime;
> - s->expire = time_second;
> + s->expire = time_uptime;
>
> if (pd->proto == IPPROTO_TCP) {
> if (s->state_flags & PFSTATE_SCRUB_TCP &&
> @@ -4198,7 +4198,7 @@ pf_tcp_track_full(struct pf_pdesc *pd, s
> src->state = dst->state = TCPS_TIME_WAIT;
>
> /* update expire time */
> - (*state)->expire = time_second;
> + (*state)->expire = time_uptime;
> if (src->state >= TCPS_FIN_WAIT_2 &&
> dst->state >= TCPS_FIN_WAIT_2)
> (*state)->timeout = PFTM_TCP_CLOSED;
> @@ -4375,7 +4375,7 @@ pf_tcp_track_sloppy(struct pf_pdesc *pd,
> src->state = dst->state = TCPS_TIME_WAIT;
>
> /* update expire time */
> - (*state)->expire = time_second;
> + (*state)->expire = time_uptime;
> if (src->state >= TCPS_FIN_WAIT_2 &&
> dst->state >= TCPS_FIN_WAIT_2)
> (*state)->timeout = PFTM_TCP_CLOSED;
> @@ -4620,7 +4620,7 @@ pf_test_state_udp(struct pf_pdesc *pd, s
> dst->state = PFUDPS_MULTIPLE;
>
> /* update expire time */
> - (*state)->expire = time_second;
> + (*state)->expire = time_uptime;
> if (src->state == PFUDPS_MULTIPLE && dst->state == PFUDPS_MULTIPLE)
> (*state)->timeout = PFTM_UDP_MULTIPLE;
> else
> @@ -4762,7 +4762,7 @@ pf_test_state_icmp(struct pf_pdesc *pd,
> return (ret);
> }
>
> - (*state)->expire = time_second;
> + (*state)->expire = time_uptime;
> (*state)->timeout = PFTM_ICMP_ERROR_REPLY;
>
> /* translate source/destination address, if necessary */
> @@ -5570,7 +5570,7 @@ pf_test_state_other(struct pf_pdesc *pd,
> dst->state = PFOTHERS_MULTIPLE;
>
> /* update expire time */
> - (*state)->expire = time_second;
> + (*state)->expire = time_uptime;
> if (src->state == PFOTHERS_MULTIPLE && dst->state == PFOTHERS_MULTIPLE)
> (*state)->timeout = PFTM_OTHER_MULTIPLE;
> else
> Index: sys/net/pf_ioctl.c
> ===================================================================
> RCS file: /opt/OpenBSD-CVS/src/sys/net/pf_ioctl.c,v
> retrieving revision 1.253
> diff -u -p -u -r1.253 pf_ioctl.c
> --- sys/net/pf_ioctl.c 8 Jul 2012 07:58:09 -0000 1.253
> +++ sys/net/pf_ioctl.c 22 Aug 2012 18:20:08 -0000
> @@ -2333,7 +2333,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t a
>
> p = psn->psn_src_nodes;
> RB_FOREACH(n, pf_src_tree, &tree_src_tracking) {
> - int secs = time_second, diff;
> + int secs = time_uptime, diff;
>
> if ((nr + 1) * sizeof(*p) > (unsigned)psn->psn_len)
> break;
> Index: sys/net/pf_norm.c
> ===================================================================
> RCS file: /opt/OpenBSD-CVS/src/sys/net/pf_norm.c,v
> retrieving revision 1.154
> diff -u -p -u -r1.154 pf_norm.c
> --- sys/net/pf_norm.c 12 May 2012 13:08:48 -0000 1.154
> +++ sys/net/pf_norm.c 22 Aug 2012 18:20:08 -0000
> @@ -173,7 +173,7 @@ void
> pf_purge_expired_fragments(void)
> {
> struct pf_fragment *frag;
> - u_int32_t expire = time_second -
> + int32_t expire = time_uptime -
> pf_default_rule.timeout[PFTM_FRAG];
>
> while ((frag = TAILQ_LAST(&pf_fragqueue, pf_fragqueue)) != NULL) {
> @@ -238,7 +238,7 @@ pf_find_fragment(struct pf_fragment_cmp
> frag = RB_FIND(pf_frag_tree, tree, (struct pf_fragment *)key);
> if (frag != NULL) {
> /* XXX Are we sure we want to update the timeout? */
> - frag->fr_timeout = time_second;
> + frag->fr_timeout = time_uptime;
> TAILQ_REMOVE(&pf_fragqueue, frag, frag_next);
> TAILQ_INSERT_HEAD(&pf_fragqueue, frag, frag_next);
> }
> @@ -314,7 +314,7 @@ pf_fillup_fragment(struct pf_fragment_cm
>
> *(struct pf_fragment_cmp *)frag = *key;
> TAILQ_INIT(&frag->fr_queue);
> - frag->fr_timeout = time_second;
> + frag->fr_timeout = time_uptime;
> frag->fr_maxlen = frent->fe_len;
>
> RB_INSERT(pf_frag_tree, &pf_frag_tree, frag);
> Index: sys/net/pfvar.h
> ===================================================================
> RCS file: /opt/OpenBSD-CVS/src/sys/net/pfvar.h,v
> retrieving revision 1.367
> diff -u -p -u -r1.367 pfvar.h
> --- sys/net/pfvar.h 26 Jul 2012 12:25:31 -0000 1.367
> +++ sys/net/pfvar.h 22 Aug 2012 18:20:08 -0000
> @@ -824,8 +824,8 @@ struct pf_state {
> struct pfi_kif *rt_kif;
> u_int64_t packets[2];
> u_int64_t bytes[2];
> - u_int32_t creation;
> - u_int32_t expire;
> + int32_t creation;
> + int32_t expire;
> u_int32_t pfsync_time;
> u_int16_t qid;
> u_int16_t pqid;
> @@ -895,8 +895,8 @@ struct pfsync_state {
> u_int32_t rule;
> u_int32_t anchor;
> u_int32_t nat_rule;
> - u_int32_t creation;
> - u_int32_t expire;
> + int32_t creation;
> + int32_t expire;
> u_int32_t packets[2][2];
> u_int32_t bytes[2][2];
> u_int32_t creatorid;
> @@ -1818,7 +1818,7 @@ int pf_normalize_tcp_stateful(struct pf_
> int *);
> int pf_normalize_mss(struct pf_pdesc *, u_int16_t);
> void pf_scrub(struct mbuf *, u_int16_t, sa_family_t, u_int8_t, u_int8_t);
> -u_int32_t
> +int32_t
> pf_state_expires(const struct pf_state *);
> void pf_purge_expired_fragments(void);
> int pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *,
>
Hello everyone,
will Florian's patch be applied in OpenBSD 5.3?