]>
Commit | Line | Data |
---|---|---|
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 | ||
46 | void | |
47 | fsm_set_state(int *var, int state) | |
48 | { | |
49 | *var = state; | |
7ebaebe2 | 50 | plog(ASL_LEVEL_NOTICE, "state changed to: %s\n", s_isakmp_state(0, 0, state)); |
65c25746 A |
51 | } |
52 | ||
53 | ||
54 | //================================ | |
55 | // Version Agnostic Events | |
56 | //================================ | |
57 | void | |
58 | fsm_api_handle_connect (struct sockaddr_storage *remote, const int connect_mode) | |
59 | { | |
60 | ||
61 | ||
62 | } | |
63 | ||
64 | void | |
65 | fsm_api_handle_disconnect (struct sockaddr_storage *remote, const char *reason) | |
66 | { | |
67 | ||
68 | ||
69 | } | |
70 | ||
71 | void | |
72 | fsm_pfkey_handle_acquire (phase2_handle_t *iph2) | |
73 | { | |
74 | ||
75 | ||
76 | } | |
77 | ||
78 | void | |
79 | fsm_pfkey_getspi_complete (phase2_handle_t *iph2) | |
80 | { | |
81 | ||
82 | } | |
83 | ||
84 | void | |
85 | fsm_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 | ||
95 | int | |
96 | fsm_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 | ||
184 | fail: | |
185 | plog(ASL_LEVEL_ERR, "Phase 1 negotiation failed.\n"); | |
186 | ike_session_unlink_phase1(iph1); | |
187 | return error; | |
188 | ||
189 | } | |
190 | ||
191 | ||
192 | int | |
193 | fsm_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) { | |
d06a7ccb | 250 | vpncontrol_notify_ike_failed(error, FROM_LOCAL, iph1_get_remote_v4_address(iph1), 0, NULL); |
65c25746 A |
251 | } |
252 | ||
253 | return error; | |
254 | } | |
255 | ||
256 | int | |
257 | fsm_ikev1_phase2_process_payloads (phase2_handle_t *iph2, vchar_t *msg) | |
258 | { | |
259 | ||
260 | int error = 0; | |
261 | #ifdef ENABLE_STATS | |
262 | struct timeval start, end; | |
263 | ||
264 | gettimeofday(&start, NULL); | |
265 | #endif | |
266 | ||
267 | switch (iph2->status) { | |
268 | /* ignore a packet */ | |
269 | case IKEV1_STATE_PHASE2_ESTABLISHED: | |
270 | case IKEV1_STATE_QUICK_I_GETSPISENT: | |
271 | case IKEV1_STATE_QUICK_R_GETSPISENT: | |
272 | return 0; | |
273 | ||
274 | case IKEV1_STATE_QUICK_I_MSG1SENT: | |
275 | error = quick_i2recv(iph2, msg); | |
276 | break; | |
277 | ||
278 | case IKEV1_STATE_QUICK_I_MSG3SENT: | |
279 | error = quick_i4recv(iph2, msg); | |
280 | break; | |
281 | ||
282 | case IKEV1_STATE_QUICK_R_START: | |
283 | error = quick_r1recv(iph2, msg); | |
284 | break; | |
285 | ||
286 | case IKEV1_STATE_QUICK_R_MSG2SENT: | |
287 | error = quick_r3recv(iph2, msg); | |
288 | break; | |
289 | ||
290 | default: | |
291 | // log invalid state | |
292 | error = -1; | |
293 | break; | |
294 | } | |
295 | ||
296 | if (error) { | |
297 | plog(ASL_LEVEL_ERR, "failed to pre-process packet.\n"); | |
298 | if (error == ISAKMP_INTERNAL_ERROR) | |
299 | fatal_error(-1); | |
300 | isakmp_info_send_n1(iph2->ph1, error, NULL); | |
301 | goto fail; | |
302 | } | |
303 | ||
304 | /* when using commit bit, status will be reached here. */ | |
305 | //if (iph2->status == PHASE2ST_ADDSA) //%%% BUG FIX - wrong place | |
306 | // return 0; | |
307 | ||
308 | /* free resend buffer */ | |
309 | if (iph2->sendbuf == NULL && iph2->status != IKEV1_STATE_QUICK_R_MSG1RCVD) { | |
310 | plog(ASL_LEVEL_ERR, | |
311 | "no buffer found as sendbuf\n"); | |
312 | error = -1; | |
313 | goto fail; | |
314 | } | |
315 | VPTRINIT(iph2->sendbuf); | |
316 | ||
317 | /* turn off schedule */ | |
318 | SCHED_KILL(iph2->scr); | |
319 | ||
320 | /* when using commit bit, will be finished here - no more packets to send */ | |
321 | if (iph2->status == IKEV1_STATE_QUICK_I_ADDSA) | |
322 | return 0; | |
323 | ||
324 | error = fsm_ikev1_phase2_send_response(iph2, msg); | |
325 | if (error) { | |
326 | plog(ASL_LEVEL_ERR, "failed to process packet.\n"); | |
327 | goto fail; | |
328 | } | |
329 | ||
330 | #ifdef ENABLE_STATS | |
331 | gettimeofday(&end, NULL); | |
332 | syslog(LOG_NOTICE, "%s(%s): %8.6f", | |
333 | "Phase 2", | |
334 | s_isakmp_state(ISAKMP_ETYPE_QUICK, iph2->side, iph2->status), | |
335 | timedelta(&start, &end)); | |
336 | #endif | |
337 | ||
338 | return 0; | |
339 | ||
340 | fail: | |
341 | plog(ASL_LEVEL_ERR, "Phase 2 negotiation failed.\n"); | |
342 | ike_session_unlink_phase2(iph2); | |
343 | return error; | |
344 | ||
345 | } | |
346 | ||
347 | int | |
348 | fsm_ikev1_phase2_send_response(phase2_handle_t *iph2, vchar_t *msg) | |
349 | { | |
350 | ||
351 | int error = 0; | |
352 | ||
353 | switch (iph2->status) { | |
354 | case IKEV1_STATE_QUICK_R_MSG1RCVD: | |
355 | error = quick_rprep(iph2, msg); | |
356 | break; | |
357 | ||
358 | case IKEV1_STATE_QUICK_I_GETSPIDONE: | |
359 | error = quick_i1send(iph2, msg); | |
360 | break; | |
361 | ||
362 | case IKEV1_STATE_QUICK_I_MSG2RCVD: | |
363 | error = quick_i3send(iph2, msg); | |
364 | break; | |
365 | ||
366 | case IKEV1_STATE_QUICK_R_GETSPIDONE: | |
367 | error = quick_r2send(iph2, msg); | |
368 | break; | |
369 | ||
370 | case IKEV1_STATE_QUICK_R_MSG3RCVD: | |
371 | error = quick_r4send(iph2, msg); | |
372 | break; | |
373 | ||
374 | case IKEV1_STATE_QUICK_R_COMMIT: | |
375 | error = quick_rfinalize(iph2, msg); | |
376 | break; | |
377 | ||
378 | default: | |
379 | // log invalid state | |
380 | error = -1; | |
381 | break;; | |
382 | } | |
383 | return error; | |
384 | ||
385 | } |