Advertisement
Guest User

Astaro patch ike_fragmentation.diff

a guest
Nov 27th, 2012
453
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.33 KB | None | 0 0
  1. From: Heiko Hund <heiko.hund@sophos.com>
  2. To: dev@lists.strongswan.org
  3. Subject: [PATCH] IKE fragmentation
  4.  
  5. The IPsec client in iOS 6 sends IKE packets split up into
  6. IKE fragment payloads in some situations. This is done
  7. regardless of whether UTM announces support for this
  8. undocumented Cisco proprietary IKE extension or not.
  9.  
  10. This patch adds support for incoming IKE fragments.
  11.  
  12. Signed-off-by: Heiko Hund <heiko.hund@sophos.com>
  13.  
  14. ---
  15. src/pluto/constants.c | 6 ++-
  16. src/pluto/constants.h | 1 +
  17. src/pluto/demux.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++
  18. src/pluto/packet.c | 27 +++++++++++
  19. src/pluto/packet.h | 29 ++++++++++++
  20. src/pluto/sa_sync.c | 1 +
  21. src/pluto/state.c | 20 ++++++++
  22. src/pluto/state.h | 13 ++++++
  23. 8 files changed, 220 insertions(+), 2 deletions(-)
  24.  
  25. diff --git a/src/pluto/constants.c b/src/pluto/constants.c
  26. index 11816ab..a257d2d 100644
  27. --- a/src/pluto/constants.c
  28. +++ b/src/pluto/constants.c
  29. @@ -278,11 +278,13 @@ const char *const payload_name[] = {
  30.  
  31. const char *const payload_name_nat_d[] = {
  32. "ISAKMP_NEXT_NAT-D",
  33. - "ISAKMP_NEXT_NAT-OA", NULL
  34. + "ISAKMP_NEXT_NAT-OA",
  35. + "ISAKMP_NEXT_IKEFRAG",
  36. + NULL
  37. };
  38.  
  39. static enum_names payload_names_nat_d =
  40. - { ISAKMP_NEXT_NATD_DRAFTS, ISAKMP_NEXT_NATOA_DRAFTS, payload_name_nat_d, NULL };
  41. + { ISAKMP_NEXT_NATD_DRAFTS, ISAKMP_NEXT_IKEFRAG, payload_name_nat_d, NULL };
  42.  
  43. enum_names payload_names =
  44. { ISAKMP_NEXT_NONE, ISAKMP_NEXT_NATOA_RFC, payload_name, &payload_names_nat_d };
  45. diff --git a/src/pluto/constants.h b/src/pluto/constants.h
  46. index 980a2a5..a69e49a 100644
  47. --- a/src/pluto/constants.h
  48. +++ b/src/pluto/constants.h
  49. @@ -528,6 +528,7 @@ extern const char *const payload_name[];
  50.  
  51. #define ISAKMP_NEXT_NATD_DRAFTS 130 /* NAT-Traversal: NAT-D (drafts) */
  52. #define ISAKMP_NEXT_NATOA_DRAFTS 131 /* NAT-Traversal: NAT-OA (drafts) */
  53. +#define ISAKMP_NEXT_IKEFRAG 132 /* IKE Fragmentation (proprietary) */
  54.  
  55. /* These values are to be used within the Type field of an Attribute (14)
  56. * ISAKMP payload.
  57. diff --git a/src/pluto/demux.c b/src/pluto/demux.c
  58. index b6a8453..89579d4 100644
  59. --- a/src/pluto/demux.c
  60. +++ b/src/pluto/demux.c
  61. @@ -1815,6 +1815,128 @@ process_packet(struct msg_digest **mdp)
  62. plog("IKE message has the Commit Flag set but Pluto doesn't implement this feature; ignoring flag");
  63. }
  64.  
  65. + /* Handle IKE fragmentation payloads */
  66. + if (md->hdr.isa_np == ISAKMP_NEXT_IKEFRAG)
  67. + {
  68. + struct isakmp_ikefrag fraghdr;
  69. + struct ike_frag *ike_frag, **i;
  70. + int last_frag_index = 0; /* index of the last fragment */
  71. + pb_stream frag_pbs;
  72. +
  73. + if (st == NULL)
  74. + {
  75. + plog("received IKE fragment, but have no state. Ignoring packet.");
  76. + return;
  77. + }
  78. +
  79. + if (!in_struct(&fraghdr, &isakmp_ikefrag_desc, &md->message_pbs, &frag_pbs)
  80. + || pbs_room(&frag_pbs) != fraghdr.isafrag_length || fraghdr.isafrag_np != 0
  81. + || fraghdr.isafrag_index == 0 || fraghdr.isafrag_index > 16)
  82. + {
  83. + SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED);
  84. + return;
  85. + }
  86. +
  87. + ike_frag = malloc_thing(struct ike_frag);
  88. + if (ike_frag == NULL)
  89. + return;
  90. +
  91. + ike_frag->md = md;
  92. + ike_frag->index = fraghdr.isafrag_index;
  93. + ike_frag->last = (fraghdr.isafrag_flags & 1);
  94. + ike_frag->size = pbs_left(&frag_pbs);
  95. + ike_frag->data = frag_pbs.cur;
  96. +
  97. + /* Strip non-ESP marker from first fragment */
  98. + if (md->iface->ike_float == TRUE && ike_frag->index == 1 && ike_frag->data[0] == 0)
  99. + {
  100. + ike_frag->data += 1;
  101. + ike_frag->size -= 1;
  102. + }
  103. +
  104. + /* Add the fragment to the state */
  105. + i = &st->ike_frags;
  106. + while (1)
  107. + {
  108. + if (ike_frag)
  109. + {
  110. + /* Still looking for a place to insert ike_frag */
  111. + if (*i == NULL || (*i)->index > ike_frag->index)
  112. + {
  113. + ike_frag->next = *i;
  114. + *i = ike_frag;
  115. + ike_frag = NULL;
  116. + }
  117. + else if ((*i)->index == ike_frag->index)
  118. + {
  119. + /* Replace fragment with same index */
  120. + struct ike_frag *old = *i;
  121. + ike_frag->next = old->next;
  122. + *i = ike_frag;
  123. + release_md(old->md);
  124. + free(old);
  125. + ike_frag = NULL;
  126. + }
  127. + }
  128. +
  129. + if (*i == NULL)
  130. + break;
  131. + else if ((*i)->last)
  132. + last_frag_index = (*i)->index;
  133. +
  134. + i = &(*i)->next;
  135. + };
  136. +
  137. + /* We have the last fragment, reassemble if complete */
  138. + if (last_frag_index)
  139. + {
  140. + size_t size = 0;
  141. + int prev_index = 0;
  142. + struct ike_frag *frag;
  143. + for (frag = st->ike_frags; frag; frag = frag->next)
  144. + {
  145. + size += frag->size;
  146. + if (frag->index != ++prev_index)
  147. + {
  148. + break; /* fragment list incomplete */
  149. + }
  150. + else if (frag->index == last_frag_index)
  151. + {
  152. + struct msg_digest *md = malloc_md();
  153. + u_int8_t *buffer = malloc(size);
  154. + size_t offset = 0;
  155. +
  156. + md->iface = frag->md->iface;
  157. + md->sender = frag->md->sender;
  158. + md->sender_port = frag->md->sender_port;
  159. +
  160. + /* Reassemble fragments in buffer */
  161. + frag = st->ike_frags;
  162. + while (frag && frag->index <= last_frag_index)
  163. + {
  164. + passert(offset + frag->size <= size);
  165. + memcpy(buffer + offset, frag->data, frag->size);
  166. + offset += frag->size;
  167. + frag = frag->next;
  168. + }
  169. +
  170. + init_pbs(&md->packet_pbs, buffer, size, "packet");
  171. +
  172. + process_packet(&md);
  173. + if (md != NULL)
  174. + release_md(md);
  175. + release_fragments(st);
  176. +
  177. + break;
  178. + }
  179. + }
  180. + }
  181. +
  182. + /* Don't release the md, taken care of by the ike_frag code */
  183. + *mdp = NULL;
  184. + return;
  185. + }
  186. +
  187. /* Set smc to describe this state's properties.
  188. * Look up the appropriate microcode based on state and
  189. * possibly Oakley Auth type.
  190. @@ -2220,6 +2342,9 @@ complete_state_transition(struct msg_digest **mdp, stf_status result)
  191. */
  192. delete_event(st);
  193.  
  194. + /* Delete IKE fragments */
  195. + release_fragments(st);
  196. +
  197. /* replace previous receive packet with latest */
  198.  
  199. free(st->st_rpacket.ptr);
  200. diff --git a/src/pluto/packet.c b/src/pluto/packet.c
  201. index 35fc4af..4aa3bdc 100644
  202. --- a/src/pluto/packet.c
  203. +++ b/src/pluto/packet.c
  204. @@ -589,6 +589,33 @@ static field_desc isanat_oa_fields[] = {
  205.  
  206. struct_desc isakmp_nat_oa = { "ISAKMP NAT-OA Payload", isanat_oa_fields, sizeof(struct isakmp_nat_oa) };
  207.  
  208. +/* ISAKMP IKE Fragmentation Payload
  209. + * Cisco proprietary, undocumented
  210. + *
  211. + * 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
  212. + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  213. + * ! Next Payload ! RESERVED ! Payload Length !
  214. + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  215. + * ! UNKNOWN (always 1) ! Index ! Flags !
  216. + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  217. + * ! !
  218. + * ~ Fragment Data ~
  219. + * ! !
  220. + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  221. + */
  222. +static field_desc isafrag_fields[] = {
  223. + { ft_mbz, 8/BITS_PER_BYTE, "next payload type", NULL },
  224. + { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
  225. + { ft_len, 16/BITS_PER_BYTE, "length", NULL },
  226. + { ft_nat, 16/BITS_PER_BYTE, "unknown", NULL },
  227. + { ft_nat, 8/BITS_PER_BYTE, "index", NULL },
  228. + { ft_nat, 8/BITS_PER_BYTE, "flags", NULL },
  229. + { ft_end, 0, NULL, NULL }
  230. +};
  231. +
  232. +struct_desc isakmp_ikefrag_desc = { "ISAKMP IKE Fragment Payload", isafrag_fields, sizeof(struct isakmp_ikefrag) };
  233. +
  234. +
  235. /* descriptor for each payload type
  236. *
  237. * There is a slight problem in that some payloads differ, depending
  238. diff --git a/src/pluto/packet.h b/src/pluto/packet.h
  239. index 1510b81..77a1cae 100644
  240. --- a/src/pluto/packet.h
  241. +++ b/src/pluto/packet.h
  242. @@ -623,6 +623,35 @@ struct isakmp_nat_oa
  243. extern struct_desc isakmp_nat_d;
  244. extern struct_desc isakmp_nat_oa;
  245.  
  246. +/* ISAKMP IKE Fragmentation Payload
  247. + * Cisco proprietary, undocumented
  248. + * This must be the first and only payload in a message,
  249. + * i.e. next payload field must always be zero.
  250. + * 1 2 3
  251. + * 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
  252. + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  253. + * ! Next Payload ! RESERVED ! Payload Length !
  254. + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  255. + * ! UNKNOWN (always 1) ! Index ! Flags !
  256. + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  257. + * ! !
  258. + * ~ Fragment Data ~
  259. + * ! !
  260. + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  261. + */
  262. +
  263. +struct isakmp_ikefrag
  264. +{
  265. + u_int8_t isafrag_np;
  266. + u_int8_t isafrag_reserved_1;
  267. + u_int16_t isafrag_length;
  268. + u_int16_t isafrag_unknown_1;
  269. + u_int8_t isafrag_index;
  270. + u_int8_t isafrag_flags;
  271. +};
  272. +
  273. +extern struct_desc isakmp_ikefrag_desc;
  274. +
  275. /* union of all payloads */
  276.  
  277. union payload {
  278. diff --git a/src/pluto/sa_sync.c b/src/pluto/sa_sync.c
  279. index 9142a97..4f09fed 100644
  280. --- a/src/pluto/sa_sync.c
  281. +++ b/src/pluto/sa_sync.c
  282. @@ -929,6 +929,7 @@ static void handle_add_state(void *data, int size, struct in_addr master_node)
  283. sync_state->st_rpacket = chunk_empty;
  284. sync_state->st_used_msgids = NULL;
  285. sync_state->st_peer_pubkey = NULL;
  286. + sync_state->ike_frags = NULL;
  287.  
  288. *st = *sync_state;
  289.  
  290. diff --git a/src/pluto/state.c b/src/pluto/state.c
  291. index b9ecbc8..52780e8 100644
  292. --- a/src/pluto/state.c
  293. +++ b/src/pluto/state.c
  294. @@ -285,6 +285,25 @@ void release_whack(struct state *st)
  295. close_any(st->st_whack_sock);
  296. }
  297.  
  298. +void release_fragments(struct state *st)
  299. +{
  300. + struct ike_frag *frag;
  301. +
  302. + if (!st)
  303. + return;
  304. +
  305. + frag = st->ike_frags;
  306. + while (frag)
  307. + {
  308. + struct ike_frag *this = frag;
  309. + frag = this->next;
  310. + release_md(this->md);
  311. + free(this);
  312. + }
  313. +
  314. + st->ike_frags = NULL;
  315. +}
  316. +
  317. /**
  318. * Delete a state object
  319. */
  320. @@ -389,6 +408,7 @@ void delete_state(struct state *st)
  321. }
  322.  
  323. unreference_key(&st->st_peer_pubkey);
  324. + release_fragments(st);
  325.  
  326. DESTROY_IF(st->st_dh);
  327.  
  328. diff --git a/src/pluto/state.h b/src/pluto/state.h
  329. index ad6edc2..3d655b1 100644
  330. --- a/src/pluto/state.h
  331. +++ b/src/pluto/state.h
  332. @@ -103,6 +103,16 @@ struct ipsec_proto_info {
  333. u_char *peer_keymat;
  334. };
  335.  
  336. +struct ike_frag
  337. +{
  338. + struct ike_frag *next;
  339. + struct msg_digest *md;
  340. + int index;
  341. + int last;
  342. + u_int8_t *data;
  343. + size_t size;
  344. +};
  345. +
  346. /* state object: record the state of a (possibly nascent) SA
  347. *
  348. * Invariants (violated only during short transitions):
  349. @@ -123,6 +133,8 @@ struct state
  350.  
  351. struct msg_digest *st_suspended_md; /* suspended state-transition */
  352.  
  353. + struct ike_frag *ike_frags; /* collected ike fragments */
  354. +
  355. struct oakley_trans_attrs st_oakley;
  356.  
  357. struct ipsec_proto_info st_ah;
  358. @@ -277,6 +289,7 @@ extern void fmt_state(bool all, struct state *st, time_t n
  359. , char *state_buf, size_t state_buf_len
  360. , char *state_buf2, size_t state_buf_len2);
  361. extern void delete_states_by_peer(ip_address *peer);
  362. +extern void release_fragments(struct state *st);
  363.  
  364. /* HA System functions */
  365. extern void state_sync_bulk(struct in_addr);
  366. --
  367. tg: (e8f0a0d..) t/0041/ike_fragmentation (depends on: t/0040/fix_policy_priority)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement