On 31.7.2012 18:20, Florian Obser wrote:
> 
> This looks like a bug in your collector, I looked at this flow:
> 
> 2012-07-30 22:58:55.002 4294967003.000 UDP 66.68.13.57:47935 -> 
> 10.161.53.99:32459 28 5349 1
> 2012-07-30 22:54:02.002 293.000 UDP 10.161.53.99:32459 -> 66.68.13.57:47935 
> 32 3616 1
> 

Hello,

could this two flows per state be product of
set state-defaults pflow in pf.conf ? You can see pf.conf in my first
mail. If it turns out that it's bug in nfdump, then this is wrong list :))

I will run your diff and post results/logs. And thank you for your time
and engagement. It's because of people like you I love and use OpenBSD :)

> These two flows are generated from the same state - there are allways
> two flows generated from one state, one for the incomming direction,
> one for outgoing. 
> 
> The various timestamps are the same for both flows on wire. I have no
> idea why it's once parsed as 4294967003.000 and once as 293.000 (this
> is the correct value btw.).
> 
> Wireshark decode looks ok (it's the second udp packet in the pcap
> file):
> [...]
> User Datagram Protocol, Src Port: 55853 (55853), Dst Port: palace-3 (9994)
> Cisco NetFlow/IPFIX
>     Version: 5
>     Count: 30
>     SysUptime: 24249000
>     Timestamp: Jul 30, 2012 23:00:05.002421728
>         CurrentSecs: 1343682005
>         CurrentNSecs: 2421728
>     FlowSequence: 591570
>     EngineType: 42
>     EngineId: 42
>     00.. .... .... .... = SamplingMode: No sampling mode configured (0)
>     ..00 0000 0000 0000 = SampleRate: 0
>     pdu 1/30
>         SrcAddr: 66.68.13.57 (66.68.13.57)
>         DstAddr: 10.161.53.99 (10.161.53.99)
>         NextHop: 0.0.0.0 (0.0.0.0)
>         InputInt: 0
>         OutputInt: 0
>         Packets: 28
>         Octets: 5349
>         [Duration: 293.000000000 seconds]
>             StartTime: 23886.000000000 seconds
>             EndTime: 24179.000000000 seconds
>         SrcPort: 47935
>         DstPort: 32459
>         padding
>         TCP Flags: 0x00
>         Protocol: 17
>         IP ToS: 0x00
>         SrcAS: 0
>         DstAS: 0
>         SrcMask: 0 (prefix: 66.68.13.57/32)
>         DstMask: 0 (prefix: 10.161.53.99/32)
>         padding
>     pdu 2/30
>         SrcAddr: 10.161.53.99 (10.161.53.99)
>         DstAddr: 66.68.13.57 (66.68.13.57)
>         NextHop: 0.0.0.0 (0.0.0.0)
>         InputInt: 0
>         OutputInt: 0
>         Packets: 32
>         Octets: 3616
>         [Duration: 293.000000000 seconds]
>             StartTime: 23886.000000000 seconds
>             EndTime: 24179.000000000 seconds
>         SrcPort: 32459
>         DstPort: 47935
>         padding
>         TCP Flags: 0x00
>         Protocol: 17
>         IP ToS: 0x00
>         SrcAS: 0
>         DstAS: 0
>         SrcMask: 0 (prefix: 10.161.53.99/32)
>         DstMask: 0 (prefix: 66.68.13.57/32)
>         padding
> [...]
> 
> We even parsed the tcpdump hexdump by hand in case wireshark fscked
> up.
> 
> Except for pfsync I'm cautiously optimistic that the two patches fix
> the pflow problem.
> 
> pfsync is an entirely different problem. When a state is synced it's
> creation time is expressed as "n seconds" ago. If the pfsync peer just
> rebooted this might be a negative number
>       st->creation = time_uptime - ntohl(sp->creation);
> but st->creation is an unsigned. (There might be a problem with
> st->expire, too)
> 
> There is a diff from dlg from last year which addresses this for
> pfsync by treating st->creation as a signed value (I'm simplifying
> here) but I'm afraid this won't help with pflow because the relevant
> fields are specified as unsigned in the RFC.
> 
> That beeing said, I'm happy to entertain that there is still a
> problem. Can you run the following diff on top, I'm using this for
> debugging. It traces the calls to pf_unlink_state and prints this to
> the console (it's added to /var/log/messages, too):
> 
>       if (ntohl(flow1->flow_start) > ntohl(flow1->flow_finish))
>               printf("pflow: start > finish, up: %lu, cr: %lu, ex: %lu, "
>                   "w: %d\n", time_uptime, st->creation, st->expire, where);
> 
> ------------------------------------------------------------------------
> 
> diff --git sys/net/if_pflow.c sys/net/if_pflow.c
> index ec07ad8..8ec15dc 100644
> --- sys/net/if_pflow.c
> +++ sys/net/if_pflow.c
> @@ -89,15 +89,15 @@ void      pflow_timeout(void *);
>  void pflow_timeout6(void *);
>  void pflow_timeout_tmpl(void *);
>  void copy_flow_data(struct pflow_flow *, struct pflow_flow *,
> -     struct pf_state *, int, int);
> +     struct pf_state *, int, int, int);
>  void copy_flow4_data(struct pflow_flow4 *, struct pflow_flow4 *,
> -     struct pf_state *, int, int);
> +     struct pf_state *, int, int, int);
>  void copy_flow6_data(struct pflow_flow6 *, struct pflow_flow6 *,
> -     struct pf_state *, int, int);
> -int  pflow_pack_flow(struct pf_state *, struct pflow_softc *);
> -int  pflow_pack_flow_ipfix(struct pf_state *, struct pflow_softc *);
> +     struct pf_state *, int, int, int);
> +int  pflow_pack_flow(struct pf_state *, struct pflow_softc *, int);
> +int  pflow_pack_flow_ipfix(struct pf_state *, struct pflow_softc *, int);
>  int  pflow_get_dynport(void);
> -int  export_pflow_if(struct pf_state*, struct pflow_softc *);
> +int  export_pflow_if(struct pf_state*, struct pflow_softc *, int);
>  int  copy_flow_to_m(struct pflow_flow *flow, struct pflow_softc *sc);
>  int  copy_flow4_to_m(struct pflow_flow4 *flow, struct pflow_softc *sc);
>  int  copy_flow6_to_m(struct pflow_flow6 *flow, struct pflow_softc *sc);
> @@ -532,7 +532,7 @@ pflow_get_mbuf(struct pflow_softc *sc, u_int16_t set_id)
>  
>  void
>  copy_flow_data(struct pflow_flow *flow1, struct pflow_flow *flow2,
> -    struct pf_state *st, int src, int dst)
> +    struct pf_state *st, int src, int dst, int where)
>  {
>       struct pf_state_key     *sk = st->key[PF_SK_WIRE];
>  
> @@ -556,6 +556,9 @@ copy_flow_data(struct pflow_flow *flow1, struct 
> pflow_flow *flow2,
>       flow1->flow_start = flow2->flow_start =
>           htonl(st->creation * 1000);
>       flow1->flow_finish = flow2->flow_finish = htonl(st->expire * 1000);
> +     if (ntohl(flow1->flow_start) > ntohl(flow1->flow_finish))
> +             printf("pflow: start > finish, up: %lu, cr: %lu, ex: %lu, "
> +                 "w: %d\n", time_uptime, st->creation, st->expire, where);
>  
>       flow1->tcp_flags = flow2->tcp_flags = 0;
>       flow1->protocol = flow2->protocol = sk->proto;
> @@ -564,7 +567,7 @@ copy_flow_data(struct pflow_flow *flow1, struct 
> pflow_flow *flow2,
>  
>  void
>  copy_flow4_data(struct pflow_flow4 *flow1, struct pflow_flow4 *flow2,
> -    struct pf_state *st, int src, int dst)
> +    struct pf_state *st, int src, int dst, int where)
>  {
>       struct pf_state_key     *sk = st->key[PF_SK_WIRE];
>  
> @@ -581,6 +584,9 @@ copy_flow4_data(struct pflow_flow4 *flow1, struct 
> pflow_flow4 *flow2,
>       flow1->flow_start = flow2->flow_start =
>           htonl(st->creation * 1000);
>       flow1->flow_finish = flow2->flow_finish = htonl(st->expire * 1000);
> +     if (ntohl(flow1->flow_start) > ntohl(flow1->flow_finish))
> +             printf("pflow: start > finish, up: %lu, cr: %lu, ex: %lu, "
> +                 "w: %d\n", time_uptime, st->creation, st->expire, where);
>  
>       flow1->protocol = flow2->protocol = sk->proto;
>       flow1->tos = flow2->tos = st->rule.ptr->tos;
> @@ -588,7 +594,7 @@ copy_flow4_data(struct pflow_flow4 *flow1, struct 
> pflow_flow4 *flow2,
>  
>  void
>  copy_flow6_data(struct pflow_flow6 *flow1, struct pflow_flow6 *flow2,
> -    struct pf_state *st, int src, int dst)
> +    struct pf_state *st, int src, int dst, int where)
>  {
>       struct pf_state_key     *sk = st->key[PF_SK_WIRE];
>       bcopy(&sk->addr[src].v6, &flow1->src_ip, sizeof(flow1->src_ip));
> @@ -606,13 +612,16 @@ copy_flow6_data(struct pflow_flow6 *flow1, struct 
> pflow_flow6 *flow2,
>       flow1->flow_start = flow2->flow_start =
>           htonl(st->creation * 1000);
>       flow1->flow_finish = flow2->flow_finish = htonl(st->expire * 1000);
> +     if (ntohl(flow1->flow_start) > ntohl(flow1->flow_finish))
> +             printf("pflow: start > finish, up: %lu, cr: %lu, ex: %lu, "
> +                 "w: %d\n", time_uptime, st->creation, st->expire, where);
>  
>       flow1->protocol = flow2->protocol = sk->proto;
>       flow1->tos = flow2->tos = st->rule.ptr->tos;
>  }
>  
>  int
> -export_pflow(struct pf_state *st)
> +export_pflow(struct pf_state *st, int where)
>  {
>       struct pflow_softc      *sc = NULL;
>       struct pf_state_key     *sk = st->key[PF_SK_WIRE];
> @@ -621,13 +630,13 @@ export_pflow(struct pf_state *st)
>               switch (sc->sc_version) {
>               case PFLOW_PROTO_5:
>                       if( sk->af == AF_INET )
> -                             export_pflow_if(st, sc);
> +                             export_pflow_if(st, sc, where);
>                       break;
>               case PFLOW_PROTO_9:
>                       /* ... fall through ... */
>               case PFLOW_PROTO_10:
>                       if( sk->af == AF_INET || sk->af == AF_INET6 )
> -                             export_pflow_if(st, sc);
> +                             export_pflow_if(st, sc, where);
>                       break;
>               default: /* NOTREACHED */
>                       break;
> @@ -638,7 +647,7 @@ export_pflow(struct pf_state *st)
>  }
>  
>  int
> -export_pflow_if(struct pf_state *st, struct pflow_softc *sc)
> +export_pflow_if(struct pf_state *st, struct pflow_softc *sc, int where)
>  {
>       struct pf_state          pfs_copy;
>       struct ifnet            *ifp = &sc->sc_if;
> @@ -649,12 +658,12 @@ export_pflow_if(struct pf_state *st, struct pflow_softc 
> *sc)
>               return (0);
>  
>       if (sc->sc_version == PFLOW_PROTO_9 || sc->sc_version == PFLOW_PROTO_10)
> -             return (pflow_pack_flow_ipfix(st, sc));
> +             return (pflow_pack_flow_ipfix(st, sc, where));
>  
>       /* PFLOW_PROTO_5 */
>       if ((st->bytes[0] < (u_int64_t)PFLOW_MAXBYTES)
>           && (st->bytes[1] < (u_int64_t)PFLOW_MAXBYTES))
> -             return (pflow_pack_flow(st, sc));
> +             return (pflow_pack_flow(st, sc, where));
>  
>       /* flow > PFLOW_MAXBYTES need special handling */
>       bcopy(st, &pfs_copy, sizeof(pfs_copy));
> @@ -665,7 +674,7 @@ export_pflow_if(struct pf_state *st, struct pflow_softc 
> *sc)
>               pfs_copy.bytes[0] = PFLOW_MAXBYTES;
>               pfs_copy.bytes[1] = 0;
>  
> -             if ((ret = pflow_pack_flow(&pfs_copy, sc)) != 0)
> +             if ((ret = pflow_pack_flow(&pfs_copy, sc, where)) != 0)
>                       return (ret);
>               if ((bytes[0] - PFLOW_MAXBYTES) > 0)
>                       bytes[0] -= PFLOW_MAXBYTES;
> @@ -675,7 +684,7 @@ export_pflow_if(struct pf_state *st, struct pflow_softc 
> *sc)
>               pfs_copy.bytes[1] = PFLOW_MAXBYTES;
>               pfs_copy.bytes[0] = 0;
>  
> -             if ((ret = pflow_pack_flow(&pfs_copy, sc)) != 0)
> +             if ((ret = pflow_pack_flow(&pfs_copy, sc, where)) != 0)
>                       return (ret);
>               if ((bytes[1] - PFLOW_MAXBYTES) > 0)
>                       bytes[1] -= PFLOW_MAXBYTES;
> @@ -684,7 +693,7 @@ export_pflow_if(struct pf_state *st, struct pflow_softc 
> *sc)
>       pfs_copy.bytes[0] = bytes[0];
>       pfs_copy.bytes[1] = bytes[1];
>  
> -     return (pflow_pack_flow(&pfs_copy, sc));
> +     return (pflow_pack_flow(&pfs_copy, sc, where));
>  }
>  
>  int
> @@ -777,7 +786,7 @@ copy_flow6_to_m(struct pflow_flow6 *flow, struct 
> pflow_softc *sc)
>  }
>  
>  int
> -pflow_pack_flow(struct pf_state *st, struct pflow_softc *sc)
> +pflow_pack_flow(struct pf_state *st, struct pflow_softc *sc, int where)
>  {
>       struct pflow_flow        flow1;
>       struct pflow_flow        flow2;
> @@ -787,9 +796,9 @@ pflow_pack_flow(struct pf_state *st, struct pflow_softc 
> *sc)
>       bzero(&flow2, sizeof(flow2));
>  
>       if (st->direction == PF_OUT)
> -             copy_flow_data(&flow1, &flow2, st, 1, 0);
> +             copy_flow_data(&flow1, &flow2, st, 1, 0, where);
>       else
> -             copy_flow_data(&flow1, &flow2, st, 0, 1);
> +             copy_flow_data(&flow1, &flow2, st, 0, 1, where);
>  
>       if (st->bytes[0] != 0) /* first flow from state */
>               ret = copy_flow_to_m(&flow1, sc);
> @@ -801,7 +810,7 @@ pflow_pack_flow(struct pf_state *st, struct pflow_softc 
> *sc)
>  }
>  
>  int
> -pflow_pack_flow_ipfix(struct pf_state *st, struct pflow_softc *sc)
> +pflow_pack_flow_ipfix(struct pf_state *st, struct pflow_softc *sc, int where)
>  {
>       struct pf_state_key     *sk = st->key[PF_SK_WIRE];
>       struct pflow_flow4       flow4_1, flow4_2;
> @@ -812,9 +821,9 @@ pflow_pack_flow_ipfix(struct pf_state *st, struct 
> pflow_softc *sc)
>               bzero(&flow4_2, sizeof(flow4_2));
>  
>               if (st->direction == PF_OUT)
> -                     copy_flow4_data(&flow4_1, &flow4_2, st, 1, 0);
> +                     copy_flow4_data(&flow4_1, &flow4_2, st, 1, 0, where);
>               else
> -                     copy_flow4_data(&flow4_1, &flow4_2, st, 0, 1);
> +                     copy_flow4_data(&flow4_1, &flow4_2, st, 0, 1, where);
>  
>               if (st->bytes[0] != 0) /* first flow from state */
>                       ret = copy_flow4_to_m(&flow4_1, sc);
> @@ -826,9 +835,9 @@ pflow_pack_flow_ipfix(struct pf_state *st, struct 
> pflow_softc *sc)
>               bzero(&flow6_2, sizeof(flow6_2));
>  
>               if (st->direction == PF_OUT)
> -                     copy_flow6_data(&flow6_1, &flow6_2, st, 1, 0);
> +                     copy_flow6_data(&flow6_1, &flow6_2, st, 1, 0, where);
>               else
> -                     copy_flow6_data(&flow6_1, &flow6_2, st, 0, 1);
> +                     copy_flow6_data(&flow6_1, &flow6_2, st, 0, 1, where);
>  
>               if (st->bytes[0] != 0) /* first flow from state */
>                       ret = copy_flow6_to_m(&flow6_1, sc);
> diff --git sys/net/if_pflow.h sys/net/if_pflow.h
> index b39e491..c258672 100644
> --- sys/net/if_pflow.h
> +++ sys/net/if_pflow.h
> @@ -270,7 +270,7 @@ struct pflowreq {
>  };
>  
>  #ifdef _KERNEL
> -int export_pflow(struct pf_state *);
> +int export_pflow(struct pf_state *, int);
>  int pflow_sysctl(int *, u_int,  void *, size_t *, void *, size_t);
>  #endif /* _KERNEL */
>  
> diff --git sys/net/if_pfsync.c sys/net/if_pfsync.c
> index fef2734..ed4d2e9 100644
> --- sys/net/if_pfsync.c
> +++ sys/net/if_pfsync.c
> @@ -769,7 +769,7 @@ pfsync_in_clr(caddr_t buf, int len, int count, int flags)
>                               nexts = RB_NEXT(pf_state_tree_id, &tree_id, st);
>                               if (st->creatorid == creatorid) {
>                                       SET(st->state_flags, PFSTATE_NOSYNC);
> -                                     pf_unlink_state(st);
> +                                     pf_unlink_state(st, 4);
>                               }
>                       }
>               } else {
> @@ -785,7 +785,7 @@ pfsync_in_clr(caddr_t buf, int len, int count, int flags)
>                                       if (si->s->creatorid == creatorid) {
>                                               SET(si->s->state_flags,
>                                                   PFSTATE_NOSYNC);
> -                                             pf_unlink_state(si->s);
> +                                             pf_unlink_state(si->s, 5);
>                                       }
>                               }
>                       }
> @@ -1091,7 +1091,7 @@ pfsync_in_del(caddr_t buf, int len, int count, int 
> flags)
>                       continue;
>               }
>               SET(st->state_flags, PFSTATE_NOSYNC);
> -             pf_unlink_state(st);
> +             pf_unlink_state(st, 6);
>       }
>  
>       return (0);
> @@ -1118,7 +1118,7 @@ pfsync_in_del_c(caddr_t buf, int len, int count, int 
> flags)
>               }
>  
>               SET(st->state_flags, PFSTATE_NOSYNC);
> -             pf_unlink_state(st);
> +             pf_unlink_state(st, 7);
>       }
>  
>       return (0);
> diff --git sys/net/pf.c sys/net/pf.c
> index 58423a1..55c36e7 100644
> --- sys/net/pf.c
> +++ sys/net/pf.c
> @@ -734,7 +734,7 @@ pf_state_key_attach(struct pf_state_key *sk, struct 
> pf_state *s, int idx)
>               TAILQ_INSERT_HEAD(&s->key[idx]->states, si, entry);
>  
>       if (olds)
> -             pf_unlink_state(olds);
> +             pf_unlink_state(olds, 1);
>  
>       return (0);
>  }
> @@ -1251,7 +1251,7 @@ pf_src_tree_remove_state(struct pf_state *s)
>  
>  /* callers should be at splsoftnet */
>  void
> -pf_unlink_state(struct pf_state *cur)
> +pf_unlink_state(struct pf_state *cur, int where)
>  {
>       splsoftassert(IPL_SOFTNET);
>  
> @@ -1271,7 +1271,7 @@ pf_unlink_state(struct pf_state *cur)
>       RB_REMOVE(pf_state_tree_id, &tree_id, cur);
>  #if NPFLOW > 0
>       if (cur->state_flags & PFSTATE_PFLOW)
> -             export_pflow(cur);
> +             export_pflow(cur, where);
>  #endif
>  #if NPFSYNC > 0
>       pfsync_delete_state(cur);
> @@ -1345,7 +1345,7 @@ pf_purge_expired_states(u_int32_t maxcheck)
>                       pf_free_state(cur);
>               } else if (pf_state_expires(cur) <= time_uptime) {
>                       /* unlink and free expired state */
> -                     pf_unlink_state(cur);
> +                     pf_unlink_state(cur, 2);
>                       if (! locked) {
>                               rw_enter_write(&pf_consistency_lock);
>                               locked = 1;
> @@ -4518,7 +4518,7 @@ pf_test_state_tcp(struct pf_pdesc *pd, struct pf_state 
> **state, u_short *reason)
>               }
>               /* XXX make sure it's the same direction ?? */
>               (*state)->src.state = (*state)->dst.state = TCPS_CLOSED;
> -             pf_unlink_state(*state);
> +             pf_unlink_state(*state, 3);
>               *state = NULL;
>               return (PF_DROP);
>       }
> diff --git sys/net/pf_ioctl.c sys/net/pf_ioctl.c
> index 99d387a..11bdc09 100644
> --- sys/net/pf_ioctl.c
> +++ sys/net/pf_ioctl.c
> @@ -1315,7 +1315,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, 
> struct proc *p)
>                               /* don't send out individual delete messages */
>                               SET(s->state_flags, PFSTATE_NOSYNC);
>  #endif
> -                             pf_unlink_state(s);
> +                             pf_unlink_state(s, 8);
>                               killed++;
>                       }
>               }
> @@ -1338,7 +1338,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, 
> struct proc *p)
>                       if (psk->psk_pfcmp.creatorid == 0)
>                               psk->psk_pfcmp.creatorid = pf_status.hostid;
>                       if ((s = pf_find_state_byid(&psk->psk_pfcmp))) {
> -                             pf_unlink_state(s);
> +                             pf_unlink_state(s, 9);
>                               psk->psk_killed = 1;
>                       }
>                       break;
> @@ -1384,7 +1384,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, 
> struct proc *p)
>                           !strcmp(psk->psk_label, s->rule.ptr->label))) &&
>                           (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname,
>                           s->kif->pfik_name))) {
> -                             pf_unlink_state(s);
> +                             pf_unlink_state(s, 10);
>                               killed++;
>                       }
>               }
> diff --git sys/net/pfvar.h sys/net/pfvar.h
> index 8ea5fa2..1c7c5e0 100644
> --- sys/net/pfvar.h
> +++ sys/net/pfvar.h
> @@ -1743,7 +1743,7 @@ extern struct pool               pf_state_scrub_pl;
>  extern void                   pf_purge_thread(void *);
>  extern void                   pf_purge_expired_src_nodes(int);
>  extern void                   pf_purge_expired_states(u_int32_t);
> -extern void                   pf_unlink_state(struct pf_state *);
> +extern void                   pf_unlink_state(struct pf_state *, int);
>  extern void                   pf_free_state(struct pf_state *);
>  extern int                    pf_state_insert(struct pfi_kif *,
>                                   struct pf_state_key *,

Reply via email to