Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- From: Heiko Hund <heiko.hund@sophos.com>
- To: dev@lists.strongswan.org
- Subject: [PATCH] IKE fragmentation
- The IPsec client in iOS 6 sends IKE packets split up into
- IKE fragment payloads in some situations. This is done
- regardless of whether UTM announces support for this
- undocumented Cisco proprietary IKE extension or not.
- This patch adds support for incoming IKE fragments.
- Signed-off-by: Heiko Hund <heiko.hund@sophos.com>
- ---
- src/pluto/constants.c | 6 ++-
- src/pluto/constants.h | 1 +
- src/pluto/demux.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++
- src/pluto/packet.c | 27 +++++++++++
- src/pluto/packet.h | 29 ++++++++++++
- src/pluto/sa_sync.c | 1 +
- src/pluto/state.c | 20 ++++++++
- src/pluto/state.h | 13 ++++++
- 8 files changed, 220 insertions(+), 2 deletions(-)
- diff --git a/src/pluto/constants.c b/src/pluto/constants.c
- index 11816ab..a257d2d 100644
- --- a/src/pluto/constants.c
- +++ b/src/pluto/constants.c
- @@ -278,11 +278,13 @@ const char *const payload_name[] = {
- const char *const payload_name_nat_d[] = {
- "ISAKMP_NEXT_NAT-D",
- - "ISAKMP_NEXT_NAT-OA", NULL
- + "ISAKMP_NEXT_NAT-OA",
- + "ISAKMP_NEXT_IKEFRAG",
- + NULL
- };
- static enum_names payload_names_nat_d =
- - { ISAKMP_NEXT_NATD_DRAFTS, ISAKMP_NEXT_NATOA_DRAFTS, payload_name_nat_d, NULL };
- + { ISAKMP_NEXT_NATD_DRAFTS, ISAKMP_NEXT_IKEFRAG, payload_name_nat_d, NULL };
- enum_names payload_names =
- { ISAKMP_NEXT_NONE, ISAKMP_NEXT_NATOA_RFC, payload_name, &payload_names_nat_d };
- diff --git a/src/pluto/constants.h b/src/pluto/constants.h
- index 980a2a5..a69e49a 100644
- --- a/src/pluto/constants.h
- +++ b/src/pluto/constants.h
- @@ -528,6 +528,7 @@ extern const char *const payload_name[];
- #define ISAKMP_NEXT_NATD_DRAFTS 130 /* NAT-Traversal: NAT-D (drafts) */
- #define ISAKMP_NEXT_NATOA_DRAFTS 131 /* NAT-Traversal: NAT-OA (drafts) */
- +#define ISAKMP_NEXT_IKEFRAG 132 /* IKE Fragmentation (proprietary) */
- /* These values are to be used within the Type field of an Attribute (14)
- * ISAKMP payload.
- diff --git a/src/pluto/demux.c b/src/pluto/demux.c
- index b6a8453..89579d4 100644
- --- a/src/pluto/demux.c
- +++ b/src/pluto/demux.c
- @@ -1815,6 +1815,128 @@ process_packet(struct msg_digest **mdp)
- plog("IKE message has the Commit Flag set but Pluto doesn't implement this feature; ignoring flag");
- }
- + /* Handle IKE fragmentation payloads */
- + if (md->hdr.isa_np == ISAKMP_NEXT_IKEFRAG)
- + {
- + struct isakmp_ikefrag fraghdr;
- + struct ike_frag *ike_frag, **i;
- + int last_frag_index = 0; /* index of the last fragment */
- + pb_stream frag_pbs;
- +
- + if (st == NULL)
- + {
- + plog("received IKE fragment, but have no state. Ignoring packet.");
- + return;
- + }
- +
- + if (!in_struct(&fraghdr, &isakmp_ikefrag_desc, &md->message_pbs, &frag_pbs)
- + || pbs_room(&frag_pbs) != fraghdr.isafrag_length || fraghdr.isafrag_np != 0
- + || fraghdr.isafrag_index == 0 || fraghdr.isafrag_index > 16)
- + {
- + SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED);
- + return;
- + }
- +
- + ike_frag = malloc_thing(struct ike_frag);
- + if (ike_frag == NULL)
- + return;
- +
- + ike_frag->md = md;
- + ike_frag->index = fraghdr.isafrag_index;
- + ike_frag->last = (fraghdr.isafrag_flags & 1);
- + ike_frag->size = pbs_left(&frag_pbs);
- + ike_frag->data = frag_pbs.cur;
- +
- + /* Strip non-ESP marker from first fragment */
- + if (md->iface->ike_float == TRUE && ike_frag->index == 1 && ike_frag->data[0] == 0)
- + {
- + ike_frag->data += 1;
- + ike_frag->size -= 1;
- + }
- +
- + /* Add the fragment to the state */
- + i = &st->ike_frags;
- + while (1)
- + {
- + if (ike_frag)
- + {
- + /* Still looking for a place to insert ike_frag */
- + if (*i == NULL || (*i)->index > ike_frag->index)
- + {
- + ike_frag->next = *i;
- + *i = ike_frag;
- + ike_frag = NULL;
- + }
- + else if ((*i)->index == ike_frag->index)
- + {
- + /* Replace fragment with same index */
- + struct ike_frag *old = *i;
- + ike_frag->next = old->next;
- + *i = ike_frag;
- + release_md(old->md);
- + free(old);
- + ike_frag = NULL;
- + }
- + }
- +
- + if (*i == NULL)
- + break;
- + else if ((*i)->last)
- + last_frag_index = (*i)->index;
- +
- + i = &(*i)->next;
- + };
- +
- + /* We have the last fragment, reassemble if complete */
- + if (last_frag_index)
- + {
- + size_t size = 0;
- + int prev_index = 0;
- + struct ike_frag *frag;
- + for (frag = st->ike_frags; frag; frag = frag->next)
- + {
- + size += frag->size;
- + if (frag->index != ++prev_index)
- + {
- + break; /* fragment list incomplete */
- + }
- + else if (frag->index == last_frag_index)
- + {
- + struct msg_digest *md = malloc_md();
- + u_int8_t *buffer = malloc(size);
- + size_t offset = 0;
- +
- + md->iface = frag->md->iface;
- + md->sender = frag->md->sender;
- + md->sender_port = frag->md->sender_port;
- +
- + /* Reassemble fragments in buffer */
- + frag = st->ike_frags;
- + while (frag && frag->index <= last_frag_index)
- + {
- + passert(offset + frag->size <= size);
- + memcpy(buffer + offset, frag->data, frag->size);
- + offset += frag->size;
- + frag = frag->next;
- + }
- +
- + init_pbs(&md->packet_pbs, buffer, size, "packet");
- +
- + process_packet(&md);
- + if (md != NULL)
- + release_md(md);
- + release_fragments(st);
- +
- + break;
- + }
- + }
- + }
- +
- + /* Don't release the md, taken care of by the ike_frag code */
- + *mdp = NULL;
- + return;
- + }
- +
- /* Set smc to describe this state's properties.
- * Look up the appropriate microcode based on state and
- * possibly Oakley Auth type.
- @@ -2220,6 +2342,9 @@ complete_state_transition(struct msg_digest **mdp, stf_status result)
- */
- delete_event(st);
- + /* Delete IKE fragments */
- + release_fragments(st);
- +
- /* replace previous receive packet with latest */
- free(st->st_rpacket.ptr);
- diff --git a/src/pluto/packet.c b/src/pluto/packet.c
- index 35fc4af..4aa3bdc 100644
- --- a/src/pluto/packet.c
- +++ b/src/pluto/packet.c
- @@ -589,6 +589,33 @@ static field_desc isanat_oa_fields[] = {
- struct_desc isakmp_nat_oa = { "ISAKMP NAT-OA Payload", isanat_oa_fields, sizeof(struct isakmp_nat_oa) };
- +/* ISAKMP IKE Fragmentation Payload
- + * Cisco proprietary, undocumented
- + *
- + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- + * ! Next Payload ! RESERVED ! Payload Length !
- + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- + * ! UNKNOWN (always 1) ! Index ! Flags !
- + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- + * ! !
- + * ~ Fragment Data ~
- + * ! !
- + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- + */
- +static field_desc isafrag_fields[] = {
- + { ft_mbz, 8/BITS_PER_BYTE, "next payload type", NULL },
- + { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
- + { ft_len, 16/BITS_PER_BYTE, "length", NULL },
- + { ft_nat, 16/BITS_PER_BYTE, "unknown", NULL },
- + { ft_nat, 8/BITS_PER_BYTE, "index", NULL },
- + { ft_nat, 8/BITS_PER_BYTE, "flags", NULL },
- + { ft_end, 0, NULL, NULL }
- +};
- +
- +struct_desc isakmp_ikefrag_desc = { "ISAKMP IKE Fragment Payload", isafrag_fields, sizeof(struct isakmp_ikefrag) };
- +
- +
- /* descriptor for each payload type
- *
- * There is a slight problem in that some payloads differ, depending
- diff --git a/src/pluto/packet.h b/src/pluto/packet.h
- index 1510b81..77a1cae 100644
- --- a/src/pluto/packet.h
- +++ b/src/pluto/packet.h
- @@ -623,6 +623,35 @@ struct isakmp_nat_oa
- extern struct_desc isakmp_nat_d;
- extern struct_desc isakmp_nat_oa;
- +/* ISAKMP IKE Fragmentation Payload
- + * Cisco proprietary, undocumented
- + * This must be the first and only payload in a message,
- + * i.e. next payload field must always be zero.
- + * 1 2 3
- + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- + * ! Next Payload ! RESERVED ! Payload Length !
- + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- + * ! UNKNOWN (always 1) ! Index ! Flags !
- + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- + * ! !
- + * ~ Fragment Data ~
- + * ! !
- + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- + */
- +
- +struct isakmp_ikefrag
- +{
- + u_int8_t isafrag_np;
- + u_int8_t isafrag_reserved_1;
- + u_int16_t isafrag_length;
- + u_int16_t isafrag_unknown_1;
- + u_int8_t isafrag_index;
- + u_int8_t isafrag_flags;
- +};
- +
- +extern struct_desc isakmp_ikefrag_desc;
- +
- /* union of all payloads */
- union payload {
- diff --git a/src/pluto/sa_sync.c b/src/pluto/sa_sync.c
- index 9142a97..4f09fed 100644
- --- a/src/pluto/sa_sync.c
- +++ b/src/pluto/sa_sync.c
- @@ -929,6 +929,7 @@ static void handle_add_state(void *data, int size, struct in_addr master_node)
- sync_state->st_rpacket = chunk_empty;
- sync_state->st_used_msgids = NULL;
- sync_state->st_peer_pubkey = NULL;
- + sync_state->ike_frags = NULL;
- *st = *sync_state;
- diff --git a/src/pluto/state.c b/src/pluto/state.c
- index b9ecbc8..52780e8 100644
- --- a/src/pluto/state.c
- +++ b/src/pluto/state.c
- @@ -285,6 +285,25 @@ void release_whack(struct state *st)
- close_any(st->st_whack_sock);
- }
- +void release_fragments(struct state *st)
- +{
- + struct ike_frag *frag;
- +
- + if (!st)
- + return;
- +
- + frag = st->ike_frags;
- + while (frag)
- + {
- + struct ike_frag *this = frag;
- + frag = this->next;
- + release_md(this->md);
- + free(this);
- + }
- +
- + st->ike_frags = NULL;
- +}
- +
- /**
- * Delete a state object
- */
- @@ -389,6 +408,7 @@ void delete_state(struct state *st)
- }
- unreference_key(&st->st_peer_pubkey);
- + release_fragments(st);
- DESTROY_IF(st->st_dh);
- diff --git a/src/pluto/state.h b/src/pluto/state.h
- index ad6edc2..3d655b1 100644
- --- a/src/pluto/state.h
- +++ b/src/pluto/state.h
- @@ -103,6 +103,16 @@ struct ipsec_proto_info {
- u_char *peer_keymat;
- };
- +struct ike_frag
- +{
- + struct ike_frag *next;
- + struct msg_digest *md;
- + int index;
- + int last;
- + u_int8_t *data;
- + size_t size;
- +};
- +
- /* state object: record the state of a (possibly nascent) SA
- *
- * Invariants (violated only during short transitions):
- @@ -123,6 +133,8 @@ struct state
- struct msg_digest *st_suspended_md; /* suspended state-transition */
- + struct ike_frag *ike_frags; /* collected ike fragments */
- +
- struct oakley_trans_attrs st_oakley;
- struct ipsec_proto_info st_ah;
- @@ -277,6 +289,7 @@ extern void fmt_state(bool all, struct state *st, time_t n
- , char *state_buf, size_t state_buf_len
- , char *state_buf2, size_t state_buf_len2);
- extern void delete_states_by_peer(ip_address *peer);
- +extern void release_fragments(struct state *st);
- /* HA System functions */
- extern void state_sync_bulk(struct in_addr);
- --
- tg: (e8f0a0d..) t/0041/ike_fragmentation (depends on: t/0040/fix_policy_priority)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement