Hi,

currently iked and the kernel treat flows as pair of source and destination
networks. The downside is that it is not possible to specify a 1-to-n relation
without repeating the source network.

The IKEv2 protocol on the other hand uses traffic selectors to
describe source and destination nets protected by a child SA, which
theoretically allow a more concise description of the same
(and some other advantages).

The attached diff is a first step towards a more traffic selector like
flow handling in iked and saves some bytes in the TS payloads by not
repeating network addresses that are used in multiple flows.

ok?

Index: config.c
===================================================================
RCS file: /cvs/src/sbin/iked/config.c,v
retrieving revision 1.50
diff -u -p -r1.50 config.c
--- config.c    11 May 2019 16:30:23 -0000      1.50
+++ config.c    30 Nov 2019 17:22:31 -0000
@@ -188,6 +188,8 @@ config_new_policy(struct iked *env)
        /* XXX caller does this again */
        TAILQ_INIT(&pol->pol_proposals);
        TAILQ_INIT(&pol->pol_sapeers);
+       TAILQ_INIT(&pol->pol_tssrc);
+       TAILQ_INIT(&pol->pol_tsdst);
        RB_INIT(&pol->pol_flows);
 
        return (pol);
@@ -197,6 +199,7 @@ void
 config_free_policy(struct iked *env, struct iked_policy *pol)
 {
        struct iked_sa          *sa;
+       struct iked_ts  *tsi;
 
        if (pol->pol_flags & IKED_POLICY_REFCNT)
                goto remove;
@@ -216,6 +219,14 @@ config_free_policy(struct iked *env, str
                return;
 
  remove:
+       while ((tsi = TAILQ_FIRST(&pol->pol_tssrc))) {
+               TAILQ_REMOVE(&pol->pol_tssrc, tsi, ts_entry);
+               free(tsi);
+       }
+       while ((tsi = TAILQ_FIRST(&pol->pol_tsdst))) {
+               TAILQ_REMOVE(&pol->pol_tsdst, tsi, ts_entry);
+               free(tsi);
+       }
        config_free_proposals(&pol->pol_proposals, 0);
        config_free_flows(env, &pol->pol_flows);
        free(pol);
@@ -732,6 +743,8 @@ config_getpolicy(struct iked *env, struc
        memcpy(pol, buf, sizeof(*pol));
        offset += sizeof(*pol);
 
+       TAILQ_INIT(&pol->pol_tssrc);
+       TAILQ_INIT(&pol->pol_tsdst);
        TAILQ_INIT(&pol->pol_proposals);
        TAILQ_INIT(&pol->pol_sapeers);
        RB_INIT(&pol->pol_flows);
Index: iked.h
===================================================================
RCS file: /cvs/src/sbin/iked/iked.h,v
retrieving revision 1.127
diff -u -p -r1.127 iked.h
--- iked.h      30 Nov 2019 15:44:07 -0000      1.127
+++ iked.h      30 Nov 2019 17:22:31 -0000
@@ -140,6 +140,13 @@ struct iked_addr {
        in_port_t                        addr_port;
 };
 
+struct iked_ts {
+       struct iked_addr                 ts_addr;
+       uint8_t                          ts_ipproto;
+       TAILQ_ENTRY(iked_ts)             ts_entry;
+};
+TAILQ_HEAD(iked_tss, iked_ts);
+
 struct iked_flow {
        struct iked_addr                 flow_src;
        struct iked_addr                 flow_dst;
@@ -277,6 +284,10 @@ struct iked_policy {
 
        struct iked_flows                pol_flows;
        size_t                           pol_nflows;
+       struct iked_tss                  pol_tssrc;     /* Traffic Selectors 
Initiator*/
+       size_t                           pol_tssrc_count;
+       struct iked_tss                  pol_tsdst;     /* Traffic Selectors 
Responder*/
+       size_t                           pol_tsdst_count;
 
        struct iked_cfg                  pol_cfg[IKED_CFG_MAX];
        unsigned int                     pol_ncfg;
@@ -759,6 +770,7 @@ void         policy_init(struct iked *);
 int     policy_lookup(struct iked *, struct iked_message *);
 struct iked_policy *
         policy_test(struct iked *, struct iked_policy *);
+int     policy_generate_ts(struct iked_policy *);
 void    policy_calc_skip_steps(struct iked_policies *);
 void    policy_ref(struct iked *, struct iked_policy *);
 void    policy_unref(struct iked *, struct iked_policy *);
Index: ikev2.c
===================================================================
RCS file: /cvs/src/sbin/iked/ikev2.c,v
retrieving revision 1.182
diff -u -p -r1.182 ikev2.c
--- ikev2.c     30 Nov 2019 15:44:07 -0000      1.182
+++ ikev2.c     30 Nov 2019 17:22:32 -0000
@@ -188,6 +188,7 @@ int
 ikev2_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
 {
        struct iked             *env = p->p_env;
+       struct iked_policy      *pol;
 
        switch (imsg->hdr.type) {
        case IMSG_CTL_RESET:
@@ -200,6 +201,10 @@ ikev2_dispatch_parent(int fd, struct pri
                if (config_getmode(env, imsg->hdr.type) == -1)
                        return (0);     /* ignore error */
                timer_del(env, &env->sc_inittmr);
+               TAILQ_FOREACH(pol, &env->sc_policies, pol_entry) {
+                       if (policy_generate_ts(pol) == -1)
+                               fatalx("%s: too many traffic selectors", 
__func__);
+               }
                if (!env->sc_passive) {
                        timer_set(env, &env->sc_inittmr, ikev2_init_ike_sa,
                            NULL);
@@ -1471,7 +1476,6 @@ ikev2_add_ts_payload(struct ibuf *buf, u
        struct iked_policy      *pol = sa->sa_policy;
        struct ikev2_tsp        *tsp;
        struct ikev2_ts         *ts;
-       struct iked_flow        *flow;
        struct iked_addr        *addr;
        struct iked_addr         pooladdr;
        uint8_t                 *ptr;
@@ -1479,28 +1483,38 @@ ikev2_add_ts_payload(struct ibuf *buf, u
        uint32_t                 av[4], bv[4], mv[4];
        struct sockaddr_in      *in4;
        struct sockaddr_in6     *in6;
+       struct iked_tss         *tss;
+       struct iked_ts          *tsi;
 
        if ((tsp = ibuf_advance(buf, sizeof(*tsp))) == NULL)
                return (-1);
        tsp->tsp_count = pol->pol_nflows;
        len = sizeof(*tsp);
 
-       RB_FOREACH(flow, iked_flows, &pol->pol_flows) {
+       if (type == IKEV2_PAYLOAD_TSi) {
+               if (sa->sa_hdr.sh_initiator) {
+                       tss = &pol->pol_tssrc;
+                       tsp->tsp_count = pol->pol_tssrc_count;
+               } else {
+                       tss = &pol->pol_tsdst;
+                       tsp->tsp_count = pol->pol_tsdst_count;
+               }
+       } else if (type == IKEV2_PAYLOAD_TSr) {
+               if (sa->sa_hdr.sh_initiator) {
+                       tss = &pol->pol_tsdst;
+                       tsp->tsp_count = pol->pol_tsdst_count;
+               } else {
+                       tss = &pol->pol_tssrc;
+                       tsp->tsp_count = pol->pol_tssrc_count;
+               }
+       } else
+               return (-1);
+
+       TAILQ_FOREACH(tsi, tss, ts_entry) {
                if ((ts = ibuf_advance(buf, sizeof(*ts))) == NULL)
                        return (-1);
 
-               if (type == IKEV2_PAYLOAD_TSi) {
-                       if (sa->sa_hdr.sh_initiator)
-                               addr = &flow->flow_src;
-                       else
-                               addr = &flow->flow_dst;
-               } else if (type == IKEV2_PAYLOAD_TSr) {
-                       if (sa->sa_hdr.sh_initiator)
-                               addr = &flow->flow_dst;
-                       else
-                               addr = &flow->flow_src;
-               } else
-                       return (-1);
+               addr = &tsi->ts_addr;
 
                /* patch remote address (if configured to 0.0.0.0) */
                if ((type == IKEV2_PAYLOAD_TSi && !sa->sa_hdr.sh_initiator) ||
@@ -1509,7 +1523,7 @@ ikev2_add_ts_payload(struct ibuf *buf, u
                                addr = &pooladdr;
                }
 
-               ts->ts_protoid = flow->flow_ipproto;
+               ts->ts_protoid = tsi->ts_ipproto;
 
                if (addr->addr_port) {
                        ts->ts_startport = addr->addr_port;
Index: ikev2.h
===================================================================
RCS file: /cvs/src/sbin/iked/ikev2.h,v
retrieving revision 1.30
diff -u -p -r1.30 ikev2.h
--- ikev2.h     11 May 2019 16:30:23 -0000      1.30
+++ ikev2.h     30 Nov 2019 17:22:32 -0000
@@ -256,6 +256,8 @@ extern struct iked_constmap ikev2_xformd
 #define IKEV2_IPV6_OVERHEAD            (40 + 8 + 28) /* IPv6 + UDP + IKE_HDR*/
 #define IKEV2_MAXLEN_IPV6_FRAG         (1280 - IKEV2_IPV6_OVERHEAD)
 
+#define IKEV2_MAXNUM_TSS               255     /* 8 bit Number of TSs field */
+
 #define IKEV2_XFORMESN_NONE            0       /* No ESN */
 #define IKEV2_XFORMESN_ESN             1       /* ESN */
 
Index: parse.y
===================================================================
RCS file: /cvs/src/sbin/iked/parse.y,v
retrieving revision 1.87
diff -u -p -r1.87 parse.y
--- parse.y     28 Nov 2019 15:52:49 -0000      1.87
+++ parse.y     30 Nov 2019 17:22:32 -0000
@@ -2675,13 +2675,12 @@ create_ike(char *name, int af, uint8_t i
        struct iked_transform   *xf;
        unsigned int             i, j, xfi, noauth;
        unsigned int             ikepropid = 1, ipsecpropid = 1;
-       struct iked_flow         flows[64];
+       struct iked_flow        *flow, *ftmp;
        static unsigned int      policy_id = 0;
        struct iked_cfg         *cfg;
        int                      ret = -1;
 
        bzero(&pol, sizeof(pol));
-       bzero(&flows, sizeof(flows));
        bzero(idstr, sizeof(idstr));
 
        pol.pol_id = ++policy_id;
@@ -2919,38 +2918,39 @@ create_ike(char *name, int af, uint8_t i
        if (hosts == NULL || hosts->src == NULL || hosts->dst == NULL)
                fatalx("create_ike: no traffic selectors/flows");
 
-       for (j = 0, ipa = hosts->src, ipb = hosts->dst; ipa && ipb;
-           ipa = ipa->next, ipb = ipb->next, j++) {
-               if (j >= nitems(flows))
-                       fatalx("create_ike: too many flows");
-               memcpy(&flows[j].flow_src.addr, &ipa->address,
+       for (ipa = hosts->src, ipb = hosts->dst; ipa && ipb;
+           ipa = ipa->next, ipb = ipb->next) {
+               if ((flow = calloc(1, sizeof(struct iked_flow))) == NULL)
+                       fatalx("%s: falied to alloc flow.", __func__);
+
+               memcpy(&flow->flow_src.addr, &ipa->address,
                    sizeof(ipa->address));
-               flows[j].flow_src.addr_af = ipa->af;
-               flows[j].flow_src.addr_mask = ipa->mask;
-               flows[j].flow_src.addr_net = ipa->netaddress;
-               flows[j].flow_src.addr_port = hosts->sport;
+               flow->flow_src.addr_af = ipa->af;
+               flow->flow_src.addr_mask = ipa->mask;
+               flow->flow_src.addr_net = ipa->netaddress;
+               flow->flow_src.addr_port = hosts->sport;
 
-               memcpy(&flows[j].flow_dst.addr, &ipb->address,
+               memcpy(&flow->flow_dst.addr, &ipb->address,
                    sizeof(ipb->address));
-               flows[j].flow_dst.addr_af = ipb->af;
-               flows[j].flow_dst.addr_mask = ipb->mask;
-               flows[j].flow_dst.addr_net = ipb->netaddress;
-               flows[j].flow_dst.addr_port = hosts->dport;
+               flow->flow_dst.addr_af = ipb->af;
+               flow->flow_dst.addr_mask = ipb->mask;
+               flow->flow_dst.addr_net = ipb->netaddress;
+               flow->flow_dst.addr_port = hosts->dport;
 
                ippn = ipa->srcnat;
                if (ippn) {
-                       memcpy(&flows[j].flow_prenat.addr, &ippn->address,
+                       memcpy(&flow->flow_prenat.addr, &ippn->address,
                            sizeof(ippn->address));
-                       flows[j].flow_prenat.addr_af = ippn->af;
-                       flows[j].flow_prenat.addr_mask = ippn->mask;
-                       flows[j].flow_prenat.addr_net = ippn->netaddress;
+                       flow->flow_prenat.addr_af = ippn->af;
+                       flow->flow_prenat.addr_mask = ippn->mask;
+                       flow->flow_prenat.addr_net = ippn->netaddress;
                } else {
-                       flows[j].flow_prenat.addr_af = 0;
+                       flow->flow_prenat.addr_af = 0;
                }
 
-               flows[j].flow_ipproto = ipproto;
+               flow->flow_ipproto = ipproto;
 
-               if (RB_INSERT(iked_flows, &pol.pol_flows, &flows[j]) == NULL)
+               if (RB_INSERT(iked_flows, &pol.pol_flows, flow) == NULL)
                        pol.pol_nflows++;
                else
                        warnx("create_ike: duplicate flow");
@@ -3042,6 +3042,10 @@ done:
                free(hosts);
        }
        iaw_free(ikecfg);
+       RB_FOREACH_SAFE(flow, iked_flows, &pol.pol_flows, ftmp) {
+               RB_REMOVE(iked_flows, &pol.pol_flows, flow);
+               free(flow);
+       }
        return (ret);
 }
 
Index: policy.c
===================================================================
RCS file: /cvs/src/sbin/iked/policy.c,v
retrieving revision 1.50
diff -u -p -r1.50 policy.c
--- policy.c    30 Nov 2019 15:44:07 -0000      1.50
+++ policy.c    30 Nov 2019 17:22:32 -0000
@@ -41,6 +41,10 @@ static __inline int
         childsa_cmp(struct iked_childsa *, struct iked_childsa *);
 static __inline int
         flow_cmp(struct iked_flow *, struct iked_flow *);
+static __inline int
+        addr_cmp(struct iked_addr *, struct iked_addr *, int);
+static __inline int
+        ts_insert_unique(struct iked_addr *, struct iked_tss *, int);
 
 
 void
@@ -385,6 +389,48 @@ sa_new(struct iked *env, uint64_t ispi, 
        }
 
        return (sa);
+}
+
+int
+policy_generate_ts(struct iked_policy *pol)
+{
+       struct iked_flow        *flow;
+
+       /* Generate list of traffic selectors from flows */
+       RB_FOREACH(flow, iked_flows, &pol->pol_flows) {
+               if (ts_insert_unique(&flow->flow_src, &pol->pol_tssrc,
+                   flow->flow_ipproto) == 1)
+                       pol->pol_tssrc_count++;
+               if (ts_insert_unique(&flow->flow_dst, &pol->pol_tsdst,
+                   flow->flow_ipproto) == 1)
+                       pol->pol_tsdst_count++;
+       }
+       if (pol->pol_tssrc_count > IKEV2_MAXNUM_TSS ||
+           pol->pol_tsdst_count > IKEV2_MAXNUM_TSS)
+               return (-1);
+
+       return (0);
+}
+
+int
+ts_insert_unique(struct iked_addr *addr, struct iked_tss *tss, int ipproto)
+{
+       struct iked_ts          *ts;
+
+       /* Remove duplicates */
+       TAILQ_FOREACH(ts, tss, ts_entry) {
+               if (addr_cmp(addr, &ts->ts_addr, 1) == 0)
+                       return (0);
+       }
+
+       if ((ts = calloc(1, sizeof(*ts))) == NULL)
+               return (-1);
+
+       ts->ts_ipproto = ipproto;
+       ts->ts_addr = *addr;
+
+       TAILQ_INSERT_TAIL(tss, ts, ts_entry);
+       return (1);
 }
 
 void

Reply via email to