]>
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; | |
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 | //================================ | |
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) { | |
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 | ||
262 | int | |
263 | fsm_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 | ||
346 | fail: | |
347 | plog(ASL_LEVEL_ERR, "Phase 2 negotiation failed.\n"); | |
348 | ike_session_unlink_phase2(iph2); | |
349 | return error; | |
350 | ||
351 | } | |
352 | ||
353 | int | |
354 | fsm_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 | } |