provide a generic packet delay functionality. packets to be delayed are marked
authorhenning <henning@openbsd.org>
Tue, 10 Jul 2018 09:28:27 +0000 (09:28 +0000)
committerhenning <henning@openbsd.org>
Tue, 10 Jul 2018 09:28:27 +0000 (09:28 +0000)
by pf in the packet header. pf_delay_pkt reads the delay value from the packet
header, schedules a timeout and re-queues the packet when the timeout fires.
ok benno sashan

sys/net/pf.c
sys/net/pf_ioctl.c
sys/net/pfvar.h
sys/sys/mbuf.h

index 77aa957..1a52323 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pf.c,v 1.1068 2018/06/18 11:00:31 procter Exp $ */
+/*     $OpenBSD: pf.c,v 1.1069 2018/07/10 09:28:27 henning Exp $ */
 
 /*
  * Copyright (c) 2001 Daniel Hartmeier
@@ -161,7 +161,7 @@ struct pf_test_ctx {
 
 struct pool             pf_src_tree_pl, pf_rule_pl, pf_queue_pl;
 struct pool             pf_state_pl, pf_state_key_pl, pf_state_item_pl;
-struct pool             pf_rule_item_pl, pf_sn_item_pl;
+struct pool             pf_rule_item_pl, pf_sn_item_pl, pf_pktdelay_pl;
 
 void                    pf_add_threshold(struct pf_threshold *);
 int                     pf_check_threshold(struct pf_threshold *);
@@ -258,6 +258,7 @@ void                         pf_state_key_link_inpcb(struct pf_state_key *,
                            struct inpcb *);
 void                    pf_state_key_unlink_inpcb(struct pf_state_key *);
 void                    pf_inpcb_unlink_state_key(struct inpcb *);
+void                    pf_pktenqueue_delayed(void *);
 
 #if NPFLOG > 0
 void                    pf_log_matches(struct pf_pdesc *, struct pf_rule *,
@@ -273,7 +274,8 @@ struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = {
        { &pf_src_tree_pl, PFSNODE_HIWAT, PFSNODE_HIWAT },
        { &pf_frent_pl, PFFRAG_FRENT_HIWAT, PFFRAG_FRENT_HIWAT },
        { &pfr_ktable_pl, PFR_KTABLE_HIWAT, PFR_KTABLE_HIWAT },
-       { &pfr_kentry_pl, PFR_KENTRY_HIWAT, PFR_KENTRY_HIWAT }
+       { &pfr_kentry_pl, PFR_KENTRY_HIWAT, PFR_KENTRY_HIWAT },
+       { &pf_pktdelay_pl, PF_PKTDELAY_MAXPKTS, PF_PKTDELAY_MAXPKTS }
 };
 
 #define STATE_LOOKUP(i, k, d, s, m)                                    \
@@ -3474,6 +3476,8 @@ pf_rule_to_actions(struct pf_rule *r, struct pf_rule_actions *a)
                a->set_prio[0] = r->set_prio[0];
                a->set_prio[1] = r->set_prio[1];
        }
+       if (r->rule_flag & PFRULE_SETDELAY)
+               a->delay = r->delay;
 }
 
 #define PF_TEST_ATTRIB(t, a)                   \
@@ -3969,6 +3973,7 @@ pf_create_state(struct pf_pdesc *pd, struct pf_rule *r, struct pf_rule *a,
 #endif /* NPFSYNC > 0 */
        s->set_prio[0] = act->set_prio[0];
        s->set_prio[1] = act->set_prio[1];
+       s->delay = act->delay;
        SLIST_INIT(&s->src_nodes);
 
        switch (pd->proto) {
@@ -7017,6 +7022,7 @@ done:
                                if (s->state_flags & PFSTATE_SETPRIO)
                                        pd.m->m_pkthdr.pf.prio = s->set_prio[0];
                        }
+                       pd.m->m_pkthdr.pf.delay = s->delay;
                } else {
                        pf_scrub(pd.m, r->scrub_flags, pd.af, r->min_ttl,
                            r->set_tos);
@@ -7029,6 +7035,7 @@ done:
                                if (r->scrub_flags & PFSTATE_SETPRIO)
                                        pd.m->m_pkthdr.pf.prio = r->set_prio[0];
                        }
+                       pd.m->m_pkthdr.pf.delay = r->delay;
                }
        }
 
@@ -7381,3 +7388,36 @@ pf_state_key_unlink_reverse(struct pf_state_key *sk)
                pf_state_key_unref(sk);
        }
 }
+
+int
+pf_delay_pkt(struct mbuf *m, u_int ifidx)
+{
+       struct pf_pktdelay      *pdy;
+
+       if ((pdy = pool_get(&pf_pktdelay_pl, PR_NOWAIT)) == NULL) {
+               m_freem(m);
+               return (ENOBUFS);
+       }
+       pdy->ifidx = ifidx;
+       pdy->m = m;
+       timeout_set(pdy->to, pf_pktenqueue_delayed, pdy);
+       timeout_add_msec(pdy->to, m->m_pkthdr.pf.delay);
+       m->m_pkthdr.pf.delay = 0;
+       return (0);
+}
+
+void
+pf_pktenqueue_delayed(void *arg)
+{
+       struct pf_pktdelay      *pdy = arg;
+       struct ifnet            *ifp;
+
+       ifp = if_get(pdy->ifidx);
+       if (ifp != NULL) {
+               if_enqueue(ifp, pdy->m);
+               if_put(ifp);
+       } else
+               m_freem(pdy->m);
+
+       pool_put(&pf_pktdelay_pl, pdy);
+}
index 8e13017..5ce121c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pf_ioctl.c,v 1.334 2018/04/24 23:05:09 bluhm Exp $ */
+/*     $OpenBSD: pf_ioctl.c,v 1.335 2018/07/10 09:28:27 henning Exp $ */
 
 /*
  * Copyright (c) 2001 Daniel Hartmeier
@@ -169,6 +169,9 @@ pfattach(int num)
            IPL_SOFTNET, 0, "pfqueue", NULL);
        pool_init(&pf_tag_pl, sizeof(struct pf_tagname), 0,
            IPL_SOFTNET, 0, "pftag", NULL);
+       pool_init(&pf_pktdelay_pl, sizeof(struct pf_pktdelay), 0,
+           IPL_SOFTNET, 0, "pfpktdelay", NULL);
+
        hfsc_initialize();
        pfr_initialize();
        pfi_initialize();
index 58b2858..17878ab 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pfvar.h,v 1.478 2018/06/18 11:00:31 procter Exp $ */
+/*     $OpenBSD: pfvar.h,v 1.479 2018/07/10 09:28:27 henning Exp $ */
 
 /*
  * Copyright (c) 2001 Daniel Hartmeier
@@ -121,7 +121,8 @@ enum        { PFTM_TCP_FIRST_PACKET, PFTM_TCP_OPENING, PFTM_TCP_ESTABLISHED,
 
 enum   { PF_NOPFROUTE, PF_ROUTETO, PF_DUPTO, PF_REPLYTO };
 enum   { PF_LIMIT_STATES, PF_LIMIT_SRC_NODES, PF_LIMIT_FRAGS,
-         PF_LIMIT_TABLES, PF_LIMIT_TABLE_ENTRIES, PF_LIMIT_MAX };
+         PF_LIMIT_TABLES, PF_LIMIT_TABLE_ENTRIES, PF_LIMIT_PKTDELAY_PKTS,
+         PF_LIMIT_MAX };
 #define PF_POOL_IDMASK         0x0f
 enum   { PF_POOL_NONE, PF_POOL_BITMASK, PF_POOL_RANDOM,
          PF_POOL_SRCHASH, PF_POOL_ROUNDROBIN, PF_POOL_LEASTSTATES };
@@ -459,11 +460,12 @@ struct pf_rule_actions {
        u_int16_t       pqid;
        u_int16_t       max_mss;
        u_int16_t       flags;
+       u_int16_t       delay;
        u_int8_t        log;
        u_int8_t        set_tos;
        u_int8_t        min_ttl;
        u_int8_t        set_prio[2];
-       u_int8_t        pad[3];
+       u_int8_t        pad[1];
 };
 
 union pf_rule_ptr {
@@ -546,6 +548,7 @@ struct pf_rule {
        u_int16_t                tag;
        u_int16_t                match_tag;
        u_int16_t                scrub_flags;
+       u_int16_t                delay;
 
        struct pf_rule_uid       uid;
        struct pf_rule_gid       gid;
@@ -605,8 +608,9 @@ struct pf_rule {
 #define        PFRULE_RETURNICMP       0x0004
 #define        PFRULE_RETURN           0x0008
 #define        PFRULE_NOSYNC           0x0010
-#define PFRULE_SRCTRACK                0x0020  /* track source states */
-#define PFRULE_RULESRCTRACK    0x0040  /* per rule */
+#define        PFRULE_SRCTRACK         0x0020  /* track source states */
+#define        PFRULE_RULESRCTRACK     0x0040  /* per rule */
+#define        PFRULE_SETDELAY         0x0080
 
 /* rule flags again */
 #define PFRULE_IFBOUND         0x00010000      /* if-bound */
@@ -619,7 +623,7 @@ struct pf_rule {
 #define PFSTATE_HIWAT          10000   /* default state table size */
 #define PFSTATE_ADAPT_START    6000    /* default adaptive timeout start */
 #define PFSTATE_ADAPT_END      12000   /* default adaptive timeout end */
-
+#define        PF_PKTDELAY_MAXPKTS     10000   /* max # of pkts held in delay queue */
 
 struct pf_rule_item {
        SLIST_ENTRY(pf_rule_item)        entry;
@@ -761,6 +765,7 @@ struct pf_state {
        int32_t                  creation;
        int32_t                  expire;
        int32_t                  pfsync_time;
+       int                      rtableid[2];   /* rtables stack and wire */
        u_int16_t                qid;
        u_int16_t                pqid;
        u_int16_t                tag;
@@ -781,14 +786,13 @@ struct pf_state {
        u_int8_t                 timeout;
        u_int8_t                 sync_state; /* PFSYNC_S_x */
        u_int8_t                 sync_updates;
-       int                      rtableid[2];   /* rtables stack and wire */
        u_int8_t                 min_ttl;
        u_int8_t                 set_tos;
        u_int8_t                 set_prio[2];
        u_int16_t                max_mss;
        u_int16_t                if_index_in;
        u_int16_t                if_index_out;
-       u_int8_t                 pad2[2];
+       u_int16_t                delay;
 };
 
 /*
@@ -1423,6 +1427,12 @@ enum pf_divert_types {
        PF_DIVERT_PACKET
 };
 
+struct pf_pktdelay {
+       struct timeout  *to;
+       struct mbuf     *m;
+       u_int            ifidx;
+};
+
 /* Fragment entries reference mbuf clusters, so base the default on that. */
 #define PFFRAG_FRENT_HIWAT     (NMBCLUSTERS / 16) /* Number of entries */
 #define PFFRAG_FRAG_HIWAT      (NMBCLUSTERS / 32) /* Number of packets */
@@ -1676,7 +1686,8 @@ extern struct pf_queuehead                 *pf_queues_active, *pf_queues_inactive;
 extern u_int32_t                ticket_pabuf;
 extern struct pool              pf_src_tree_pl, pf_sn_item_pl, pf_rule_pl;
 extern struct pool              pf_state_pl, pf_state_key_pl, pf_state_item_pl,
-                                   pf_rule_item_pl, pf_queue_pl;
+                                   pf_rule_item_pl, pf_queue_pl,
+                                   pf_pktdelay_pl;
 extern struct pool              pf_state_scrub_pl;
 extern struct ifnet            *sync_ifp;
 extern struct pf_rule           pf_default_rule;
@@ -1785,6 +1796,7 @@ int       pf_translate_af(struct pf_pdesc *);
 void   pf_route(struct pf_pdesc *, struct pf_rule *, struct pf_state *);
 void   pf_route6(struct pf_pdesc *, struct pf_rule *, struct pf_state *);
 void   pf_init_threshold(struct pf_threshold *, u_int32_t, u_int32_t);
+int    pf_delay_pkt(struct mbuf *, u_int);
 
 void   pfr_initialize(void);
 int    pfr_match_addr(struct pfr_ktable *, struct pf_addr *, sa_family_t);
index 14a43b4..8c2f21b 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: mbuf.h,v 1.235 2018/02/11 00:24:13 dlg Exp $  */
+/*     $OpenBSD: mbuf.h,v 1.236 2018/07/10 09:28:27 henning Exp $      */
 /*     $NetBSD: mbuf.h,v 1.19 1996/02/09 18:25:14 christos Exp $       */
 
 /*
@@ -100,10 +100,11 @@ struct pkthdr_pf {
        struct inpcb    *inp;           /* connected pcb for outgoing packet */
        u_int32_t        qid;           /* queue id */
        u_int16_t        tag;           /* tag id */
+       u_int16_t        delay;         /* delay packet by X ms */
        u_int8_t         flags;
        u_int8_t         routed;
        u_int8_t         prio;
-       u_int8_t         pad[3];
+       u_int8_t         pad[1];
 };
 
 /* pkthdr_pf.flags */