]> git.saurik.com Git - apple/ipsec.git/blame - ipsec-tools/racoon/fsm.c
ipsec-292.tar.gz
[apple/ipsec.git] / ipsec-tools / racoon / fsm.c
CommitLineData
65c25746
A
1/*
2 * Copyright (c) 2008, 2012, 2013 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23
24#include "fsm.h"
25
26#include <stdlib.h>
27#include <sys/types.h>
28#include <sys/param.h>
29#include <sys/queue.h>
30
31#include "var.h"
32#include "misc.h"
33#include "session.h"
34#include "isakmp.h"
35#include "ike_session.h"
36#include "isakmp_var.h"
37#include "isakmp_ident.h"
38#include "isakmp_agg.h"
39#include "isakmp_quick.h"
40#include "isakmp_inf.h"
41#include "vpn_control_var.h"
42
43#include "plog.h"
44#include "schedule.h"
45
46void
47fsm_set_state(int *var, int state)
48{
49 *var = state;
50 plog(ASL_LEVEL_DEBUG, "****** state changed to: %s\n", s_isakmp_state(0, 0, state));
51}
52
53
54//================================
55// Version Agnostic Events
56//================================
57void
58fsm_api_handle_connect (struct sockaddr_storage *remote, const int connect_mode)
59{
60
61
62}
63
64void
65fsm_api_handle_disconnect (struct sockaddr_storage *remote, const char *reason)
66{
67
68
69}
70
71void
72fsm_pfkey_handle_acquire (phase2_handle_t *iph2)
73{
74
75
76}
77
78void
79fsm_pfkey_getspi_complete (phase2_handle_t *iph2)
80{
81
82}
83
84void
85fsm_isakmp_initial_pkt (vchar_t *pkt, struct sockaddr_storage *local, struct sockaddr_storage *remote)
86{
87
88
89}
90
91//================================
92// IKEv1 Events
93//================================
94
95int
96fsm_ikev1_phase1_process_payloads (phase1_handle_t *iph1, vchar_t *msg)
97{
98
99 int error = 0;
100#ifdef ENABLE_STATS
101 struct timeval start, end;
102
103 gettimeofday(&start, NULL);
104#endif
105
106 switch (iph1->status) {
107 case IKEV1_STATE_PHASE1_ESTABLISHED:
108 return 0; // ignore - already established
109
110 case IKEV1_STATE_IDENT_I_MSG1SENT:
111 error = ident_i2recv(iph1, msg);
112 break;
113
114 case IKEV1_STATE_IDENT_I_MSG3SENT:
115 error = ident_i4recv(iph1, msg);
116 break;
117
118 case IKEV1_STATE_IDENT_I_MSG5SENT:
119 error = ident_i6recv(iph1, msg);
120 break;
121
122 case IKEV1_STATE_IDENT_R_START:
123 error = ident_r1recv(iph1, msg);
124 if (error) {
125 plog(ASL_LEVEL_ERR, "failed to pre-process packet.\n");
126 goto fail;
127 }
128 break;
129
130 case IKEV1_STATE_IDENT_R_MSG2SENT:
131 error = ident_r3recv(iph1, msg);
132 break;
133
134 case IKEV1_STATE_IDENT_R_MSG4SENT:
135 error = ident_r5recv(iph1, msg);
136 break;
137
138 case IKEV1_STATE_AGG_R_START:
139 error = agg_r1recv(iph1, msg);
140 if (error) {
141 plog(ASL_LEVEL_ERR, "failed to pre-process packet.\n");
142 goto fail;
143 }
144 break;
145
146 case IKEV1_STATE_AGG_I_MSG1SENT:
147 error = agg_i2recv(iph1, msg);
148 break;
149
150 case IKEV1_STATE_AGG_R_MSG2SENT:
151 error = agg_r3recv(iph1, msg);
152 break;
153
154 default:
155 // log invalid state
156 error = -1;
157 break;
158 }
159 if (error)
160 return 0; // ignore error and keep phase 1 handle
161
162 VPTRINIT(iph1->sendbuf);
163 /* turn off schedule */
164 SCHED_KILL(iph1->scr);
165
166 /* send */
167 plog(ASL_LEVEL_DEBUG, "===\n");
168 if ((error = fsm_ikev1_phase1_send_response(iph1, msg))) {
169 plog(ASL_LEVEL_ERR, "failed to process packet.\n");
170 goto fail;
171 }
172
173#ifdef ENABLE_STATS
174 gettimeofday(&end, NULL);
175 syslog(LOG_NOTICE, "%s(%s): %8.6f",
176 "Phase 1", s_isakmp_state(iph1->etype, iph1->side, iph1->status),
177 timedelta(&start, &end));
178#endif
179 if (FSM_STATE_IS_ESTABLISHED(iph1->status))
180 ikev1_phase1_established(iph1);
181
182 return 0;
183
184fail:
185 plog(ASL_LEVEL_ERR, "Phase 1 negotiation failed.\n");
186 ike_session_unlink_phase1(iph1);
187 return error;
188
189}
190
191
192int
193fsm_ikev1_phase1_send_response(phase1_handle_t *iph1, vchar_t *msg)
194{
195
196 int error = 0;
197
198 switch (iph1->status) {
199 case IKEV1_STATE_IDENT_I_START:
200 error = ident_i1send(iph1, msg);
201 break;
202
203 case IKEV1_STATE_IDENT_I_MSG2RCVD:
204 error = ident_i3send(iph1, msg);
205 break;
206
207 case IKEV1_STATE_IDENT_I_MSG4RCVD:
208 error = ident_i5send(iph1, msg);
209 break;
210
211 case IKEV1_STATE_IDENT_I_MSG6RCVD:
212 error = ident_ifinalize(iph1, msg);
213 break;
214
215 case IKEV1_STATE_IDENT_R_MSG1RCVD:
216 error = ident_r2send(iph1, msg);
217 break;
218
219 case IKEV1_STATE_IDENT_R_MSG3RCVD:
220 error = ident_r4send(iph1, msg);
221 break;
222
223 case IKEV1_STATE_IDENT_R_MSG5RCVD:
224 error = ident_r6send(iph1, msg);
225 break;
226
227 case IKEV1_STATE_AGG_I_START:
228 error = agg_i1send(iph1, msg);
229 break;
230
231 case IKEV1_STATE_AGG_I_MSG2RCVD:
232 error = agg_i3send(iph1, msg);
233 break;
234
235 case IKEV1_STATE_AGG_R_MSG1RCVD:
236 error = agg_r2send(iph1, msg);
237 break;
238
239 case IKEV1_STATE_AGG_R_MSG3RCVD:
240 error = agg_rfinalize(iph1, msg);
241 break;
242
243 default:
244 // log invalid state
245 error = -1;
246 break;;
247 }
248
249 if (error) {
250 u_int32_t address;
251 if (iph1->remote->ss_family == AF_INET)
252 address = ((struct sockaddr_in *)iph1->remote)->sin_addr.s_addr;
253 else {
254 address = 0;
255 }
256 vpncontrol_notify_ike_failed(error, FROM_LOCAL, address, 0, NULL);
257 }
258
259 return error;
260}
261
262int
263fsm_ikev1_phase2_process_payloads (phase2_handle_t *iph2, vchar_t *msg)
264{
265
266 int error = 0;
267#ifdef ENABLE_STATS
268 struct timeval start, end;
269
270 gettimeofday(&start, NULL);
271#endif
272
273 switch (iph2->status) {
274 /* ignore a packet */
275 case IKEV1_STATE_PHASE2_ESTABLISHED:
276 case IKEV1_STATE_QUICK_I_GETSPISENT:
277 case IKEV1_STATE_QUICK_R_GETSPISENT:
278 return 0;
279
280 case IKEV1_STATE_QUICK_I_MSG1SENT:
281 error = quick_i2recv(iph2, msg);
282 break;
283
284 case IKEV1_STATE_QUICK_I_MSG3SENT:
285 error = quick_i4recv(iph2, msg);
286 break;
287
288 case IKEV1_STATE_QUICK_R_START:
289 error = quick_r1recv(iph2, msg);
290 break;
291
292 case IKEV1_STATE_QUICK_R_MSG2SENT:
293 error = quick_r3recv(iph2, msg);
294 break;
295
296 default:
297 // log invalid state
298 error = -1;
299 break;
300 }
301
302 if (error) {
303 plog(ASL_LEVEL_ERR, "failed to pre-process packet.\n");
304 if (error == ISAKMP_INTERNAL_ERROR)
305 fatal_error(-1);
306 isakmp_info_send_n1(iph2->ph1, error, NULL);
307 goto fail;
308 }
309
310 /* when using commit bit, status will be reached here. */
311 //if (iph2->status == PHASE2ST_ADDSA) //%%% BUG FIX - wrong place
312 // return 0;
313
314 /* free resend buffer */
315 if (iph2->sendbuf == NULL && iph2->status != IKEV1_STATE_QUICK_R_MSG1RCVD) {
316 plog(ASL_LEVEL_ERR,
317 "no buffer found as sendbuf\n");
318 error = -1;
319 goto fail;
320 }
321 VPTRINIT(iph2->sendbuf);
322
323 /* turn off schedule */
324 SCHED_KILL(iph2->scr);
325
326 /* when using commit bit, will be finished here - no more packets to send */
327 if (iph2->status == IKEV1_STATE_QUICK_I_ADDSA)
328 return 0;
329
330 error = fsm_ikev1_phase2_send_response(iph2, msg);
331 if (error) {
332 plog(ASL_LEVEL_ERR, "failed to process packet.\n");
333 goto fail;
334 }
335
336#ifdef ENABLE_STATS
337 gettimeofday(&end, NULL);
338 syslog(LOG_NOTICE, "%s(%s): %8.6f",
339 "Phase 2",
340 s_isakmp_state(ISAKMP_ETYPE_QUICK, iph2->side, iph2->status),
341 timedelta(&start, &end));
342#endif
343
344 return 0;
345
346fail:
347 plog(ASL_LEVEL_ERR, "Phase 2 negotiation failed.\n");
348 ike_session_unlink_phase2(iph2);
349 return error;
350
351}
352
353int
354fsm_ikev1_phase2_send_response(phase2_handle_t *iph2, vchar_t *msg)
355{
356
357 int error = 0;
358
359 switch (iph2->status) {
360 case IKEV1_STATE_QUICK_R_MSG1RCVD:
361 error = quick_rprep(iph2, msg);
362 break;
363
364 case IKEV1_STATE_QUICK_I_GETSPIDONE:
365 error = quick_i1send(iph2, msg);
366 break;
367
368 case IKEV1_STATE_QUICK_I_MSG2RCVD:
369 error = quick_i3send(iph2, msg);
370 break;
371
372 case IKEV1_STATE_QUICK_R_GETSPIDONE:
373 error = quick_r2send(iph2, msg);
374 break;
375
376 case IKEV1_STATE_QUICK_R_MSG3RCVD:
377 error = quick_r4send(iph2, msg);
378 break;
379
380 case IKEV1_STATE_QUICK_R_COMMIT:
381 error = quick_rfinalize(iph2, msg);
382 break;
383
384 default:
385 // log invalid state
386 error = -1;
387 break;;
388 }
389 return error;
390
391}