2 * Copyright (c) 2008 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
27 #include <sys/types.h>
28 #include "ike_session.h"
29 #include "ipsecMessageTracer.h"
31 #include "nattraversal.h"
35 const char *ipsecSessionInvalidEventString
= "Invalid Event";
36 const char *ipsecSessionString
= "IPSEC";
38 /* tells us the event's description */
39 const char * const ipsecSessionEventStrings
[IPSECSESSIONEVENTCODE_MAX
] = { CONSTSTR("NONE") /* index place holder */,
40 CONSTSTR("IKE Packet: transmit success"),
41 CONSTSTR("IKE Packet: transmit failed"),
42 CONSTSTR("IKE Packet: receive success"),
43 CONSTSTR("IKE Packet: receive failed"),
44 CONSTSTR("IKEv1 Phase1 Initiator: success"),
45 CONSTSTR("IKEv1 Phase1 Initiator: failed"),
46 CONSTSTR("IKEv1 Phase1 Initiator: dropped"),
47 CONSTSTR("IKEv1 Phase1 Responder: success"),
48 CONSTSTR("IKEv1 Phase1 Responder: failed"),
49 CONSTSTR("IKEv1 Phase1 Responder: drop"),
50 CONSTSTR("IKEv1 Phase1: maximum retransmits"),
51 CONSTSTR("IKEv1 Phase1 AUTH: success"),
52 CONSTSTR("IKEv1 Phase1 AUTH: failed"),
53 CONSTSTR("IKEv1 Dead-Peer-Detection: request transmitted"),
54 CONSTSTR("IKEv1 Dead-Peer-Detection: response received"),
55 CONSTSTR("IKEv1 Dead-Peer-Detection: request retransmitted"),
56 CONSTSTR("IKEv1 Dead-Peer-Detection: request received"),
57 CONSTSTR("IKEv1 Dead-Peer-Detection: response transmitted"),
58 CONSTSTR("IKEv1 Dead-Peer-Detection: response retransmitted"),
59 CONSTSTR("IKEv1 Dead-Peer-Detection: maximum retransmits"),
60 CONSTSTR("IKEv1 Config: retransmited"),
61 CONSTSTR("IKEv1 Mode-Config: success"),
62 CONSTSTR("IKEv1 Mode-Config: failed"),
63 CONSTSTR("IKEv1 Mode-Config: dropped"),
64 CONSTSTR("IKEv1 XAUTH: success"),
65 CONSTSTR("IKEv1 XAUTH: failed"),
66 CONSTSTR("IKEv1 XAUTH: dropped"),
67 CONSTSTR("IKEv1 Phase2 Initiator: success"),
68 CONSTSTR("IKEv1 Phase2 Initiator: failed"),
69 CONSTSTR("IKEv1 Phase2 Initiator: dropped"),
70 CONSTSTR("IKEv1 Phase2 Responder: success"),
71 CONSTSTR("IKEv1 Phase2 Responder: fail"),
72 CONSTSTR("IKEv1 Phase2 Responder: drop"),
73 CONSTSTR("IKEv1 Phase2: maximum retransmits"),
74 CONSTSTR("IKEv1 Phase2 AUTH: success"),
75 CONSTSTR("IKEv1 Phase2 AUTH: failed"),
76 CONSTSTR("IKEv1 Information-Notice: transmit success"),
77 CONSTSTR("IKEv1 Information-Notice: transmit failed"),
78 CONSTSTR("IKEv1 Information-Notice: receive success"),
79 CONSTSTR("IKEv1 Information-Notice: receive failed"),
82 /* tells us if we can ignore the failure_reason passed into the event tracer */
83 const int const ipsecSessionEventIgnoreReason
[IPSECSESSIONEVENTCODE_MAX
] = {TRUE
/* index place holder */,
128 ipsecSessionEventCodeToString (ipsecSessionEventCode_t eventCode
)
130 if (eventCode
<= IPSECSESSIONEVENTCODE_NONE
|| eventCode
>= IPSECSESSIONEVENTCODE_MAX
)
131 return ipsecSessionInvalidEventString
;
132 return(ipsecSessionEventStrings
[eventCode
]);
136 ipsecSessionGetConnectionDomain (ike_session_t
*session
)
139 if (session
->is_cisco_ipsec
) {
140 if (session
->established
) {
141 return CISCOIPSECVPN_CONNECTION_ESTABLISHED_DOMAIN
;
143 return CISCOIPSECVPN_CONNECTION_NOTESTABLISHED_DOMAIN
;
145 } else if (session
->is_l2tpvpn_ipsec
) {
146 if (session
->established
) {
147 return L2TPIPSECVPN_CONNECTION_ESTABLISHED_DOMAIN
;
149 return L2TPIPSECVPN_CONNECTION_NOTESTABLISHED_DOMAIN
;
151 } else if (session
->is_btmm_ipsec
) {
152 if (session
->established
) {
153 return BTMMIPSEC_CONNECTION_ESTABLISHED_DOMAIN
;
155 return BTMMIPSEC_CONNECTION_NOTESTABLISHED_DOMAIN
;
158 if (session
->established
) {
159 return PLAINIPSEC_CONNECTION_ESTABLISHED_DOMAIN
;
161 return PLAINIPSEC_CONNECTION_NOTESTABLISHED_DOMAIN
;
165 return PLAINIPSECDOMAIN
;
169 ipsecSessionGetConnectionLessDomain (ike_session_t
*session
)
172 if (session
->is_cisco_ipsec
) {
173 return CISCOIPSECVPN_CONNECTION_NOTESTABLISHED_DOMAIN
;
174 } else if (session
->is_l2tpvpn_ipsec
) {
175 return L2TPIPSECVPN_CONNECTION_NOTESTABLISHED_DOMAIN
;
176 } else if (session
->is_btmm_ipsec
) {
177 return BTMMIPSEC_CONNECTION_NOTESTABLISHED_DOMAIN
;
179 return PLAINIPSEC_CONNECTION_NOTESTABLISHED_DOMAIN
;
182 return PLAINIPSECDOMAIN
;
186 ipsecSessionGetPhaseDomain (ike_session_t
*session
)
189 if (session
->is_cisco_ipsec
) {
190 return CISCOIPSECVPN_PHASE_DOMAIN
;
191 } else if (session
->is_l2tpvpn_ipsec
) {
192 return L2TPIPSECVPN_PHASE_DOMAIN
;
193 } else if (session
->is_btmm_ipsec
) {
194 return BTMMIPSEC_PHASE_DOMAIN
;
197 return PLAINIPSEC_PHASE_DOMAIN
;
202 ipsecSessionLogEvent (ike_session_t
*session
, const char *event_msg
)
210 m
= asl_new(ASL_TYPE_MSG
);
211 asl_set(m
, ASL_KEY_FACILITY
, ipsecSessionGetPhaseDomain(session
));
212 asl_set(m
, ASL_KEY_MSG
, ipsecSessionString
);
213 asl_log(NULL
, m
, ASL_LEVEL_NOTICE
, "%s", event_msg
);
218 ipsecSessionTracerStart (ike_session_t
*session
)
220 if (session
== NULL
) {
223 bzero(&session
->stats
, sizeof(session
->stats
));
224 bzero(&session
->stop_timestamp
, sizeof(session
->stop_timestamp
));
225 bzero(&session
->estab_timestamp
, sizeof(session
->estab_timestamp
));
226 gettimeofday(&session
->start_timestamp
, NULL
);
227 ipsecSessionLogEvent(session
, CONSTSTR("Connecting."));
231 ipsecSessionTracerEvent (ike_session_t
*session
, ipsecSessionEventCode_t eventCode
, const char *event
, const char *failure_reason
)
235 if (session
== NULL
) {
236 ipsecSessionLogEvent(session
, CONSTSTR("tracer failed. (Invalid session)."));
239 if (eventCode
<= IPSECSESSIONEVENTCODE_NONE
|| eventCode
>= IPSECSESSIONEVENTCODE_MAX
) {
240 ipsecSessionLogEvent(session
, CONSTSTR("tracer failed. (Invalid event code)."));
244 ipsecSessionLogEvent(session
, CONSTSTR("tracer failed. (Invalid event)."));
248 if (failure_reason
) {
249 if (!session
->term_reason
&&
250 !ipsecSessionEventIgnoreReason
[eventCode
]) {
251 session
->term_reason
= failure_reason
;
255 session
->stats
.counters
[eventCode
]++;
257 snprintf(buf
, sizeof(buf
), "%s. (%s).", ipsecSessionEventCodeToString(eventCode
), event
);
258 ipsecSessionLogEvent(session
, CONSTSTR(buf
));
262 ipsecSessionTracerLogFailureRate (ike_session_t
*session
, const char *signature
, double failure_rate
)
266 const char *domain
= ipsecSessionGetPhaseDomain(session
);
268 if (!signature
|| failure_rate
<= 0.001) {
272 m
= asl_new(ASL_TYPE_MSG
);
273 asl_set(m
, "com.apple.message.domain", domain
);
274 asl_set(m
, ASL_KEY_FACILITY
, domain
);
275 asl_set(m
, ASL_KEY_MSG
, ipsecSessionString
);
276 asl_set(m
, "com.apple.message.result", "noop");
277 asl_set(m
, "com.apple.message.signature", signature
);
278 snprintf(buf
, sizeof(buf
), "%.3f", failure_rate
);
279 asl_set(m
, "com.apple.message.value", buf
); // stuff the up time into value
280 asl_log(NULL
, m
, ASL_LEVEL_NOTICE
, "%s. (Failure-Rate = %s).", signature
, buf
);
285 ipsecSessionTracerLogStop (ike_session_t
*session
, int caused_by_failure
, const char *reason
)
290 const char *domain
= (session
->established
)? ipsecSessionGetConnectionDomain(session
) : ipsecSessionGetConnectionLessDomain(session
);
292 m
= asl_new(ASL_TYPE_MSG
);
293 asl_set(m
, "com.apple.message.domain", domain
);
294 asl_set(m
, ASL_KEY_FACILITY
, domain
);
295 asl_set(m
, ASL_KEY_MSG
, ipsecSessionString
);
296 if (caused_by_failure
||
297 (reason
&& reason
!= ike_session_stopped_by_flush
&& reason
!= ike_session_stopped_by_vpn_disconnect
)) {
298 asl_set(m
, "com.apple.message.result", CONSTSTR("failure")); // failure
300 asl_set(m
, "com.apple.message.result", CONSTSTR("success")); // success
303 if (session
->natt_flags
& NAT_DETECTED_ME
) {
304 snprintf(nat_buf
, sizeof(nat_buf
), "%s. NAT detected by Me", reason
);
305 asl_set(m
, "com.apple.message.signature", nat_buf
);
306 } else if (session
->natt_flags
& NAT_DETECTED_PEER
) {
307 snprintf(nat_buf
, sizeof(nat_buf
), "%s. NAT detected by Peer", reason
);
308 asl_set(m
, "com.apple.message.signature", nat_buf
);
310 asl_set(m
, "com.apple.message.signature", reason
);
313 // reason was NULL; make sure success/failure have different signature
314 if (caused_by_failure
) {
315 asl_set(m
, "com.apple.message.signature", CONSTSTR("Internal/Server-side error"));
317 asl_set(m
, "com.apple.message.signature", CONSTSTR("User/System initiated the disconnect"));
320 if (session
->established
) {
321 snprintf(buf
, sizeof(buf
), "%8.6f", timedelta(&session
->estab_timestamp
, &session
->stop_timestamp
));
322 asl_set(m
, "com.apple.message.value", buf
); // stuff the up time into value
323 asl_log(NULL
, m
, ASL_LEVEL_NOTICE
, "Disconnecting. (Connection was up for, %s seconds).", buf
);
325 snprintf(buf
, sizeof(buf
), "%8.6f", timedelta(&session
->start_timestamp
, &session
->stop_timestamp
));
326 asl_set(m
, "com.apple.message.value2", buf
); /// stuff the negoing time into value2
327 asl_log(NULL
, m
, ASL_LEVEL_NOTICE
, "Disconnecting. (Connection tried to negotiate for, %s seconds).", buf
);
333 ipsecSessionTracerStop (ike_session_t
*session
, int caused_by_failure
, const char *reason
)
335 if (session
== NULL
) {
339 gettimeofday(&session
->stop_timestamp
, NULL
);
341 ipsecSessionTracerLogStop(session
, caused_by_failure
, reason
);
343 // go thru counters logging failure-rate events
344 if (session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKE_PACKET_TX_FAIL
]) {
345 ipsecSessionTracerLogFailureRate(session
,
346 CONSTSTR("IKE Packets Transmit Failure-Rate Statistic"),
347 get_percentage((double)session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKE_PACKET_TX_FAIL
], (double)session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKE_PACKET_TX_SUCC
]));
349 if (session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKE_PACKET_RX_FAIL
]) {
350 ipsecSessionTracerLogFailureRate(session
,
351 CONSTSTR("IKE Packets Receive Failure-Rate Statistic"),
352 get_percentage((double)session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKE_PACKET_RX_FAIL
], (double)session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKE_PACKET_RX_SUCC
]));
354 if (session
->version
== IKE_VERSION_1
) {
355 if (session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH1_MAX_RETRANSMIT
] ||
356 session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH1_INIT_FAIL
] ||
357 session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH1_RESP_FAIL
]) {
358 ipsecSessionTracerLogFailureRate(session
,
359 CONSTSTR("IKE Phase1 Failure-Rate Statistic"),
360 get_percentage((double)(session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH1_MAX_RETRANSMIT
] +
361 session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH1_INIT_FAIL
] +
362 session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH1_RESP_FAIL
]),
363 (double)(session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH1_INIT_SUCC
] +
364 session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH1_RESP_SUCC
])));
366 if (session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH1_INIT_FAIL
]) {
367 ipsecSessionTracerLogFailureRate(session
,
368 CONSTSTR("IKE Phase1 Initiator Failure-Rate Statistic"),
369 get_percentage((double)session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH1_INIT_FAIL
], (double)session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH1_INIT_SUCC
]));
371 if (session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH1_RESP_FAIL
]) {
372 ipsecSessionTracerLogFailureRate(session
,
373 CONSTSTR("IKE Phase1 Responder Failure-Rate Statistic"),
374 get_percentage((double)session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH1_RESP_FAIL
], (double)session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH1_RESP_SUCC
]));
376 if (session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH1_AUTH_FAIL
]) {
377 ipsecSessionTracerLogFailureRate(session
,
378 CONSTSTR("IKE Phase1 Authentication Failure-Rate Statistic"),
379 get_percentage((double)session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH1_AUTH_FAIL
], (double)session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH1_AUTH_SUCC
]));
381 if (session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_DPD_MAX_RETRANSMIT
]) {
382 ipsecSessionTracerLogFailureRate(session
,
383 CONSTSTR("IKE Dead-Peer-Detection Failure-Rate Statistic"),
384 get_percentage((double)session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_DPD_MAX_RETRANSMIT
],
385 (double)(session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_DPD_MAX_RETRANSMIT
] +
386 session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_DPD_INIT_REQ
])));
388 if (session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_DPD_INIT_RETRANSMIT
] ||
389 session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_DPD_RESP_RETRANSMIT
]) {
390 ipsecSessionTracerLogFailureRate(session
,
391 CONSTSTR("IKE Dead-Peer-Detect Retransmit-Rate Statistic"),
392 get_percentage((double)(session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_DPD_INIT_RETRANSMIT
] +
393 session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_DPD_RESP_RETRANSMIT
]),
394 (double)(session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_DPD_INIT_REQ
] +
395 session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_DPD_RESP_REQ
])));
397 if (session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_MODECFG_FAIL
]) {
398 ipsecSessionTracerLogFailureRate(session
,
399 CONSTSTR("IKE MODE-Config Failure-Rate Statistic"),
400 get_percentage((double)session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_MODECFG_FAIL
], (double)session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_MODECFG_SUCC
]));
402 if (session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_XAUTH_FAIL
]) {
403 ipsecSessionTracerLogFailureRate(session
,
404 CONSTSTR("IKE XAUTH Failure-Rate Statistic"),
405 get_percentage((double)session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_XAUTH_FAIL
], (double)session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_XAUTH_SUCC
]));
407 if (session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH2_MAX_RETRANSMIT
] ||
408 session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH2_INIT_FAIL
] ||
409 session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH2_RESP_FAIL
]) {
410 ipsecSessionTracerLogFailureRate(session
,
411 CONSTSTR("IKE Phase2 Failure-Rate Statistic"),
412 get_percentage((double)(session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH2_MAX_RETRANSMIT
] +
413 session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH2_INIT_FAIL
] +
414 session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH2_RESP_FAIL
]),
415 (double)(session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH2_INIT_SUCC
] +
416 session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH2_RESP_FAIL
])));
418 if (session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH2_INIT_FAIL
]) {
419 ipsecSessionTracerLogFailureRate(session
,
420 CONSTSTR("IKE Phase2 Initiator Failure-Rate Statistic"),
421 get_percentage((double)session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH2_INIT_FAIL
], (double)session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH2_INIT_SUCC
]));
423 if (session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH2_RESP_FAIL
]) {
424 ipsecSessionTracerLogFailureRate(session
,
425 CONSTSTR("IKE Phase2 Responder Failure-Rate Statistic"),
426 get_percentage((double)session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH2_RESP_FAIL
], (double)session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH2_RESP_SUCC
]));
428 if (session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH2_AUTH_FAIL
]) {
429 ipsecSessionTracerLogFailureRate(session
,
430 CONSTSTR("IKE Phase2 Authentication Failure-Rate Statistics"),
431 get_percentage((double)session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH2_AUTH_FAIL
], (double)session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_PH2_AUTH_SUCC
]));
433 if (session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_INFO_NOTICE_TX_FAIL
]) {
434 ipsecSessionTracerLogFailureRate(session
,
435 CONSTSTR("IKE Information-Notice Transmit Failure-Rate Statistic"),
436 get_percentage((double)session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_INFO_NOTICE_TX_FAIL
], (double)session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_INFO_NOTICE_TX_FAIL
]));
438 if (session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_INFO_NOTICE_RX_FAIL
]) {
439 ipsecSessionTracerLogFailureRate(session
,
440 CONSTSTR("IKE Information-Notice Receive Failure-Rate Statistic"),
441 get_percentage((double)session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_INFO_NOTICE_RX_FAIL
], (double)session
->stats
.counters
[IPSECSESSIONEVENTCODE_IKEV1_INFO_NOTICE_RX_SUCC
]));
447 ipsecSessionTracerLogEstablished (ike_session_t
*session
)
450 const char *domain
= ipsecSessionGetConnectionLessDomain(session
);
452 m
= asl_new(ASL_TYPE_MSG
);
453 asl_set(m
, "com.apple.message.domain", domain
);
454 asl_set(m
, ASL_KEY_FACILITY
, domain
);
455 asl_set(m
, ASL_KEY_MSG
, ipsecSessionString
);
456 asl_set(m
, "com.apple.message.result", "success"); // success
457 asl_set(m
, "com.apple.message.signature", "success");
458 asl_log(NULL
, m
, ASL_LEVEL_NOTICE
, "Connected.");