Hello all.

This patch splits off IMSG_CFG_POLICY into four messages:

  IMSG_CFG_POLICY_BEGIN
  IMSG_CFG_POLICY_PROPOSAL
  IMSG_CFG_POLICY_FLOW
  IMSG_CFG_POLICY_COMMIT

Each new policy should start with IMSG_CFG_POLICY_BEGIN, then proceed
any number of proposals and flows, and then commit policy. I decided
not to use ticket system because I see no race sources.

Now we can have long, long policies in your iked.conf. Previously we were
limited by maximum imsg packet size (MAX_IMSGSIZE) which is 16 kilobytes
currently.

This patch complements previous one:
http://marc.info/?l=openbsd-tech&m=130583217730436&w=2
Those patches are totally independent and may be applied in any order and
combination.

Both patches were tested on i386.

-- 
  Best wishes,
    Vadim Zhukov

A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing in e-mail?


Index: ikev2.c
===================================================================
RCS file: /cvs/src/sbin/iked/ikev2.c,v
retrieving revision 1.55
diff -u -p -r1.55 ikev2.c
--- ikev2.c     9 May 2011 11:15:18 -0000       1.55
+++ ikev2.c     20 May 2011 09:48:06 -0000
@@ -133,8 +133,14 @@ ikev2_dispatch_parent(int fd, struct pri
                return (config_getsocket(env, imsg, ikev2_msg_cb));
        case IMSG_PFKEY_SOCKET:
                return (config_getpfkey(env, imsg));
-       case IMSG_CFG_POLICY:
-               return (config_getpolicy(env, imsg));
+       case IMSG_CFG_POLICY_BEGIN:
+               return (config_getpolicy_begin(env, imsg));
+       case IMSG_CFG_POLICY_PROPOSAL:
+               return (config_getpolicy_proposal(env, imsg));
+       case IMSG_CFG_POLICY_FLOW:
+               return (config_getpolicy_flow(env, imsg));
+       case IMSG_CFG_POLICY_COMMIT:
+               return (config_getpolicy_commit(env, imsg));
        case IMSG_CFG_USER:
                return (config_getuser(env, imsg));
        case IMSG_COMPILE:
Index: config.c
===================================================================
RCS file: /cvs/src/sbin/iked/config.c,v
retrieving revision 1.12
diff -u -p -r1.12 config.c
--- config.c    9 May 2011 11:15:18 -0000       1.12
+++ config.c    20 May 2011 09:48:06 -0000
@@ -45,6 +45,10 @@
 #include "iked.h"
 #include "ikev2.h"
 
+
+static struct iked_policy *newpol = NULL;
+
+
 struct iked_sa *
 config_new_sa(struct iked *env, int initiator)
 {
@@ -584,122 +588,167 @@ config_setpolicy(struct iked *env, struc
 {
        struct iked_proposal    *prop;
        struct iked_flow        *flow;
-       struct iked_transform   *xform;
-       size_t                   size, iovcnt, j, c = 0;
        struct iovec             iov[IOV_MAX];
+       unsigned int             i;
 
-       iovcnt = 1;
-       size = sizeof(*pol);
-       TAILQ_FOREACH(prop, &pol->pol_proposals, prop_entry) {
-               size += (prop->prop_nxforms * sizeof(*xform)) +
-                   (sizeof(*prop));
-               iovcnt += prop->prop_nxforms + 1;
+       if (env->sc_opts & IKED_OPT_NOACTION) {
+               print_policy(pol);
+               return (0);
        }
 
-       size += pol->pol_nflows * sizeof(*flow);
-       iovcnt += pol->pol_nflows;
-
-       if (iovcnt > IOV_MAX) {
-               log_warn("%s: too many proposals/flows", __func__);
+       if (proc_compose_imsg(env, id, IMSG_CFG_POLICY_BEGIN, -1,
+           pol, sizeof(*pol)) == -1)
                return (-1);
-       }
-
-       iov[c].iov_base = pol;
-       iov[c++].iov_len = sizeof(*pol);
 
        TAILQ_FOREACH(prop, &pol->pol_proposals, prop_entry) {
-               iov[c].iov_base = prop;
-               iov[c++].iov_len = sizeof(*prop);
-
-               for (j = 0; j < prop->prop_nxforms; j++) {
-                       xform = prop->prop_xforms + j;
+               iov[0].iov_base = prop;
+               iov[0].iov_len = sizeof(*prop);
 
-                       iov[c].iov_base = xform;
-                       iov[c++].iov_len = sizeof(*xform);
+               for (i = 1; i <= prop->prop_nxforms; i++) {
+                       if (i >= IOV_MAX) {
+                               log_warn("%s: too many proposals", __func__);
+                               return (-1);
+                       }
+                       iov[i].iov_base = prop->prop_xforms + (i - 1);
+                       iov[i].iov_len = sizeof(struct iked_transform);
                }
+
+               if (proc_composev_imsg(env, id, IMSG_CFG_POLICY_PROPOSAL, -1,
+                   iov, i) == -1)
+                       return (-1);
        }
 
        RB_FOREACH(flow, iked_flows, &pol->pol_flows) {
-               iov[c].iov_base = flow;
-               iov[c++].iov_len = sizeof(*flow);
+               if (proc_compose_imsg(env, id, IMSG_CFG_POLICY_FLOW, -1,
+                   flow, sizeof(struct iked_flow)) == -1)
+                       return (-1);
        }
 
-       if (env->sc_opts & IKED_OPT_NOACTION) {
-               print_policy(pol);
-               return (0);
+       if (proc_compose_imsg(env, id, IMSG_CFG_POLICY_COMMIT, -1,
+           NULL, 0) == -1)
+               return (-1);
+
+       return (0);
+}
+
+int
+config_getpolicy_begin(struct iked *env, struct imsg *imsg)
+{
+       u_int8_t        *buf = (u_int8_t *)imsg->data;
+
+       IMSG_SIZE_CHECK(imsg, newpol);
+       log_debug("%s: start receiving policy", __func__);
+
+       if (newpol != NULL) {
+               log_warnx("%s: previous policy was not commited");
+               config_free_policy(env, newpol);
        }
 
-       if (proc_composev_imsg(env, id, IMSG_CFG_POLICY, -1,
-           iov, iovcnt) == -1)
-               return (-1);
+       if ((newpol = config_new_policy(NULL)) == NULL)
+               fatal("config_getpolicy_begin: new policy");
+
+       memcpy(newpol, buf, sizeof(*newpol));
+
+       TAILQ_INIT(&newpol->pol_proposals);
+       RB_INIT(&newpol->pol_flows);
+
+       newpol->pol_nproposals = 0;
+       newpol->pol_nflows = 0;
 
        return (0);
 }
 
 int
-config_getpolicy(struct iked *env, struct imsg *imsg)
+config_getpolicy_proposal(struct iked *env, struct imsg *imsg)
 {
-       struct iked_policy      *pol;
+       u_int8_t                *buf = (u_int8_t *)imsg->data;
+       off_t                    offset = 0;
        struct iked_proposal     pp, *prop;
        struct iked_transform    xf, *xform;
-       struct iked_flow        *flow;
-       off_t                    offset = 0;
-       u_int                    i, j;
-       u_int8_t                *buf = (u_int8_t *)imsg->data;
+       u_int                    i;
 
-       IMSG_SIZE_CHECK(imsg, pol);
-       log_debug("%s: received policy", __func__);
+       IMSG_SIZE_CHECK(imsg, prop);
+       log_debug("%s: receiving proposal", __func__);
 
-       if ((pol = config_new_policy(NULL)) == NULL)
-               fatal("config_getpolicy: new policy");
+       memcpy(&pp, buf + offset, sizeof(pp));
+       offset += sizeof(pp);
+       if (imsg->hdr.len < (pp.prop_nxforms * sizeof(xf)) + offset)
+               fatalx("bad length imsg received");
 
-       memcpy(pol, buf, sizeof(*pol));
-       offset += sizeof(*pol);
+       if ((prop = config_add_proposal(&newpol->pol_proposals,
+           pp.prop_id, pp.prop_protoid)) == NULL)
+               fatal("config_getpolicy: add proposal");
 
-       TAILQ_INIT(&pol->pol_proposals);
-       RB_INIT(&pol->pol_flows);
+       for (i = 0; i < pp.prop_nxforms; i++) {
+               memcpy(&xf, buf + offset, sizeof(xf));
+               offset += sizeof(xf);
 
-       for (i = 0; i < pol->pol_nproposals; i++) {
-               memcpy(&pp, buf + offset, sizeof(pp));
-               offset += sizeof(pp);
-
-               if ((prop = config_add_proposal(&pol->pol_proposals,
-                   pp.prop_id, pp.prop_protoid)) == NULL)
-                       fatal("config_getpolicy: add proposal");
-
-               for (j = 0; j < pp.prop_nxforms; j++) {
-                       memcpy(&xf, buf + offset, sizeof(xf));
-                       offset += sizeof(xf);
-
-                       if ((xform = config_add_transform(prop, xf.xform_type,
-                           xf.xform_id, xf.xform_length,
-                           xf.xform_keylength)) == NULL)
-                               fatal("config_getpolicy: add transform");
-               }
+               if ((xform = config_add_transform(prop, xf.xform_type,
+                   xf.xform_id, xf.xform_length,
+                   xf.xform_keylength)) == NULL)
+                       fatal("config_getpolicy: add transform");
        }
 
-       for (i = 0; i < pol->pol_nflows; i++) {
-               if ((flow = calloc(1, sizeof(*flow))) == NULL)
-                       fatal("config_getpolicy: new flow");
+       newpol->pol_nproposals++;
+       return (0);
+}
 
-               memcpy(flow, buf + offset, sizeof(*flow));
-               offset += sizeof(*flow);
+int
+config_getpolicy_flow(struct iked *env, struct imsg *imsg)
+{
+       struct iked_flow        *flow;
+       u_int8_t                *buf = (u_int8_t *)imsg->data;
 
-               RB_INSERT(iked_flows, &pol->pol_flows, flow);
+       IMSG_SIZE_CHECK(imsg, flow);
+       log_debug("%s: receiving flow", __func__);
+
+       if ((flow = calloc(1, sizeof(*flow))) == NULL)
+               fatal("config_getpolicy: new flow");
+
+       memcpy(flow, buf, sizeof(*flow));
+       RB_INSERT(iked_flows, &newpol->pol_flows, flow);
+
+       newpol->pol_nflows++;
+       return (0);
+}
+
+int
+config_getpolicy_commit(struct iked *env, struct imsg *imsg)
+{
+       /* XXX no data used, how to cope? */
+
+       if (newpol == NULL) {
+               log_warnx("%s: no policy started", __func__);
+               goto fail;
+       }
+       if (newpol->pol_nproposals == 0) {
+               log_warnx("%s: no proposals in policy", __func__);
+               goto fail;
+       }
+       if (newpol->pol_nflows == 0) {
+               log_warnx("%s: no flows in policy", __func__);
+               goto fail;
        }
 
-       TAILQ_INSERT_TAIL(&env->sc_policies, pol, pol_entry);
+       TAILQ_INSERT_TAIL(&env->sc_policies, newpol, pol_entry);
 
-       if (pol->pol_flags & IKED_POLICY_DEFAULT) {
+       if (newpol->pol_flags & IKED_POLICY_DEFAULT) {
                /* Only one default policy, just free/unref the old one */
                if (env->sc_defaultcon != NULL)
                        config_free_policy(env, env->sc_defaultcon);
-               env->sc_defaultcon = pol;
+               env->sc_defaultcon = newpol;
        }
 
-       print_policy(pol);
-
+       print_policy(newpol);
+       newpol = NULL;
        return (0);
+
+fail:
+       if (newpol != NULL) {
+               config_free_policy(env, newpol);
+               newpol = NULL;
+       }
+       return (-1);
 }
 
 int
Index: types.h
===================================================================
RCS file: /cvs/src/sbin/iked/types.h,v
retrieving revision 1.10
diff -u -p -r1.10 types.h
--- types.h     5 May 2011 12:17:10 -0000       1.10
+++ types.h     20 May 2011 09:48:06 -0000
@@ -92,13 +92,16 @@ enum imsg_type {
        IMSG_UDP_SOCKET,
        IMSG_PFKEY_SOCKET,
        IMSG_IKE_MESSAGE,
-       IMSG_CFG_POLICY,
        IMSG_CFG_USER,
        IMSG_CERTREQ,
        IMSG_CERT,
        IMSG_CERTVALID,
        IMSG_CERTINVALID,
-       IMSG_AUTH
+       IMSG_AUTH,
+       IMSG_CFG_POLICY_BEGIN,
+       IMSG_CFG_POLICY_PROPOSAL,
+       IMSG_CFG_POLICY_FLOW,
+       IMSG_CFG_POLICY_COMMIT
 };
 
 enum privsep_procid {
Index: iked.h
===================================================================
RCS file: /cvs/src/sbin/iked/iked.h,v
retrieving revision 1.41
diff -u -p -r1.41 iked.h
--- iked.h      9 May 2011 11:15:18 -0000       1.41
+++ iked.h      20 May 2011 09:51:26 -0000
@@ -547,7 +547,10 @@ int         config_setreset(struct iked *, u_in
 int     config_getreset(struct iked *, struct imsg *);
 int     config_setpolicy(struct iked *, struct iked_policy *,
            enum privsep_procid);
-int     config_getpolicy(struct iked *, struct imsg *);
+int     config_getpolicy_begin(struct iked *, struct imsg *);
+int     config_getpolicy_proposal(struct iked *, struct imsg *);
+int     config_getpolicy_flow(struct iked *, struct imsg *);
+int     config_getpolicy_commit(struct iked *, struct imsg *);
 int     config_setsocket(struct iked *, struct sockaddr_storage *, in_port_t,
            enum privsep_procid);
 int     config_getsocket(struct iked *env, struct imsg *,

Reply via email to