2 * Copyright (C) 2013 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
5 * Copyright (C) 2013 Martin Willi
6 * Copyright (C) 2013 revosec AG
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 #include "cmd_connection.h"
24 #include <utils/debug.h>
25 #include <processing/jobs/callback_job.h>
26 #include <threading/thread.h>
29 typedef enum profile_t profile_t
;
30 typedef struct private_cmd_connection_t private_cmd_connection_t
;
33 * Connection profiles we support
50 ENUM(profile_names
, PROF_V2_PUB
, PROF_V1_HYBRID_AM
,
65 * Private data of an cmd_connection_t object.
67 struct private_cmd_connection_t
{
70 * Public cmd_connection_t interface.
72 cmd_connection_t
public;
75 * Process ID to terminate on failure
80 * List of local traffic selectors
82 linked_list_t
*local_ts
;
85 * List of remote traffic selectors
87 linked_list_t
*remote_ts
;
90 * Hostname to connect to
95 * Server identity, or NULL to use host
110 * Is a private key configured
115 * Selected connection profile
121 * Shut down application
123 static void terminate(pid_t pid
)
129 * Create peer config with associated ike config
131 static peer_cfg_t
* create_peer_cfg(private_cmd_connection_t
*this)
134 peer_cfg_t
*peer_cfg
;
135 u_int16_t local_port
, remote_port
= IKEV2_UDP_PORT
;
136 ike_version_t version
= IKE_ANY
;
137 bool aggressive
= FALSE
;
139 switch (this->profile
)
144 case PROF_V2_PUB_EAP
:
148 case PROF_V1_XAUTH_AM
:
149 case PROF_V1_XAUTH_PSK_AM
:
150 case PROF_V1_HYBRID_AM
:
155 case PROF_V1_XAUTH_PSK
:
161 local_port
= charon
->socket
->get_port(charon
->socket
, FALSE
);
162 if (local_port
!= IKEV2_UDP_PORT
)
164 remote_port
= IKEV2_NATT_PORT
;
166 ike_cfg
= ike_cfg_create(version
, TRUE
, FALSE
, "0.0.0.0", FALSE
, local_port
,
167 this->host
, FALSE
, remote_port
, FRAGMENTATION_NO
, 0);
168 ike_cfg
->add_proposal(ike_cfg
, proposal_create_default(PROTO_IKE
));
169 peer_cfg
= peer_cfg_create("cmd", ike_cfg
,
170 CERT_SEND_IF_ASKED
, UNIQUE_REPLACE
, 1, /* keyingtries */
171 36000, 0, /* rekey 10h, reauth none */
172 600, 600, /* jitter, over 10min */
173 TRUE
, aggressive
, TRUE
, /* mobike, aggressive, pull */
174 30, 0, /* DPD delay, timeout */
175 FALSE
, NULL
, NULL
); /* mediation */
176 peer_cfg
->add_virtual_ip(peer_cfg
, host_create_from_string("0.0.0.0", 0));
182 * Add a single auth cfg of given class to peer cfg
184 static void add_auth_cfg(private_cmd_connection_t
*this, peer_cfg_t
*peer_cfg
,
185 bool local
, auth_class_t
class)
187 identification_t
*id
;
190 auth
= auth_cfg_create();
191 auth
->add(auth
, AUTH_RULE_AUTH_CLASS
, class);
194 id
= identification_create_from_string(this->identity
);
200 auth
->add(auth
, AUTH_RULE_EAP_IDENTITY
,
201 identification_create_from_string(this->xautheap
));
203 case AUTH_CLASS_XAUTH
:
204 auth
->add(auth
, AUTH_RULE_XAUTH_IDENTITY
,
205 identification_create_from_string(this->xautheap
));
216 id
= identification_create_from_string(this->server
);
220 id
= identification_create_from_string(this->host
);
222 auth
->add(auth
, AUTH_RULE_IDENTITY_LOOSE
, TRUE
);
224 auth
->add(auth
, AUTH_RULE_IDENTITY
, id
);
225 peer_cfg
->add_auth_cfg(peer_cfg
, auth
, local
);
229 * Attach authentication configs to peer config
231 static bool add_auth_cfgs(private_cmd_connection_t
*this, peer_cfg_t
*peer_cfg
)
233 if (this->profile
== PROF_UNDEF
)
237 this->profile
= PROF_V2_PUB
;
241 this->profile
= PROF_V2_EAP
;
244 switch (this->profile
)
247 case PROF_V2_PUB_EAP
:
251 case PROF_V1_XAUTH_AM
:
254 DBG1(DBG_CFG
, "missing private key for profile %N",
255 profile_names
, this->profile
);
263 switch (this->profile
)
266 add_auth_cfg(this, peer_cfg
, TRUE
, AUTH_CLASS_PUBKEY
);
267 add_auth_cfg(this, peer_cfg
, FALSE
, AUTH_CLASS_ANY
);
270 add_auth_cfg(this, peer_cfg
, TRUE
, AUTH_CLASS_EAP
);
271 add_auth_cfg(this, peer_cfg
, FALSE
, AUTH_CLASS_ANY
);
273 case PROF_V2_PUB_EAP
:
274 add_auth_cfg(this, peer_cfg
, TRUE
, AUTH_CLASS_PUBKEY
);
275 add_auth_cfg(this, peer_cfg
, TRUE
, AUTH_CLASS_EAP
);
276 add_auth_cfg(this, peer_cfg
, FALSE
, AUTH_CLASS_ANY
);
280 add_auth_cfg(this, peer_cfg
, TRUE
, AUTH_CLASS_PUBKEY
);
281 add_auth_cfg(this, peer_cfg
, FALSE
, AUTH_CLASS_PUBKEY
);
284 case PROF_V1_XAUTH_AM
:
285 add_auth_cfg(this, peer_cfg
, TRUE
, AUTH_CLASS_PUBKEY
);
286 add_auth_cfg(this, peer_cfg
, TRUE
, AUTH_CLASS_XAUTH
);
287 add_auth_cfg(this, peer_cfg
, FALSE
, AUTH_CLASS_PUBKEY
);
289 case PROF_V1_XAUTH_PSK
:
290 case PROF_V1_XAUTH_PSK_AM
:
291 add_auth_cfg(this, peer_cfg
, TRUE
, AUTH_CLASS_PSK
);
292 add_auth_cfg(this, peer_cfg
, TRUE
, AUTH_CLASS_XAUTH
);
293 add_auth_cfg(this, peer_cfg
, FALSE
, AUTH_CLASS_PSK
);
296 case PROF_V1_HYBRID_AM
:
297 add_auth_cfg(this, peer_cfg
, TRUE
, AUTH_CLASS_XAUTH
);
298 add_auth_cfg(this, peer_cfg
, FALSE
, AUTH_CLASS_PUBKEY
);
307 * Attach child config to peer config
309 static child_cfg_t
* create_child_cfg(private_cmd_connection_t
*this)
311 child_cfg_t
*child_cfg
;
312 traffic_selector_t
*ts
;
313 lifetime_cfg_t lifetime
= {
315 .life
= 10800 /* 3h */,
316 .rekey
= 10200 /* 2h50min */,
317 .jitter
= 300 /* 5min */
321 child_cfg
= child_cfg_create("cmd", &lifetime
,
322 NULL
, FALSE
, MODE_TUNNEL
, /* updown, hostaccess */
323 ACTION_NONE
, ACTION_NONE
, ACTION_NONE
, FALSE
,
324 0, 0, NULL
, NULL
, 0);
325 child_cfg
->add_proposal(child_cfg
, proposal_create_default(PROTO_ESP
));
326 while (this->local_ts
->remove_first(this->local_ts
, (void**)&ts
) == SUCCESS
)
328 child_cfg
->add_traffic_selector(child_cfg
, TRUE
, ts
);
330 if (this->remote_ts
->get_count(this->remote_ts
) == 0)
332 /* add a 0.0.0.0/0 TS for remote side if none given */
333 ts
= traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE
,
334 "0.0.0.0", 0, "255.255.255.255", 65535);
335 this->remote_ts
->insert_last(this->remote_ts
, ts
);
337 while (this->remote_ts
->remove_first(this->remote_ts
,
338 (void**)&ts
) == SUCCESS
)
340 child_cfg
->add_traffic_selector(child_cfg
, FALSE
, ts
);
347 * Initiate the configured connection
349 static job_requeue_t
initiate(private_cmd_connection_t
*this)
351 peer_cfg_t
*peer_cfg
;
352 child_cfg_t
*child_cfg
;
353 pid_t pid
= this->pid
;
357 DBG1(DBG_CFG
, "unable to initiate, missing --host option");
359 return JOB_REQUEUE_NONE
;
363 DBG1(DBG_CFG
, "unable to initiate, missing --identity option");
365 return JOB_REQUEUE_NONE
;
368 peer_cfg
= create_peer_cfg(this);
370 if (!add_auth_cfgs(this, peer_cfg
))
372 peer_cfg
->destroy(peer_cfg
);
374 return JOB_REQUEUE_NONE
;
377 child_cfg
= create_child_cfg(this);
378 peer_cfg
->add_child_cfg(peer_cfg
, child_cfg
->get_ref(child_cfg
));
380 if (charon
->controller
->initiate(charon
->controller
, peer_cfg
, child_cfg
,
381 controller_cb_empty
, NULL
, 0) != SUCCESS
)
385 return JOB_REQUEUE_NONE
;
389 * Create a traffic selector from string, add to list
391 static void add_ts(private_cmd_connection_t
*this,
392 linked_list_t
*list
, char *string
)
394 traffic_selector_t
*ts
;
396 ts
= traffic_selector_create_from_cidr(string
, 0, 0, 65535);
399 DBG1(DBG_CFG
, "invalid traffic selector: %s", string
);
402 list
->insert_last(list
, ts
);
406 * Parse profile name identifier
408 static void set_profile(private_cmd_connection_t
*this, char *name
)
412 profile
= enum_from_name(profile_names
, name
);
415 DBG1(DBG_CFG
, "unknown connection profile: %s", name
);
418 this->profile
= profile
;
421 METHOD(cmd_connection_t
, handle
, bool,
422 private_cmd_connection_t
*this, cmd_option_type_t opt
, char *arg
)
429 case CMD_OPT_REMOTE_IDENTITY
:
432 case CMD_OPT_IDENTITY
:
433 this->identity
= arg
;
435 case CMD_OPT_EAP_IDENTITY
:
436 case CMD_OPT_XAUTH_USER
:
437 this->xautheap
= arg
;
442 this->key_seen
= TRUE
;
444 case CMD_OPT_LOCAL_TS
:
445 add_ts(this, this->local_ts
, arg
);
447 case CMD_OPT_REMOTE_TS
:
448 add_ts(this, this->remote_ts
, arg
);
450 case CMD_OPT_PROFILE
:
451 set_profile(this, arg
);
459 METHOD(cmd_connection_t
, destroy
, void,
460 private_cmd_connection_t
*this)
462 this->local_ts
->destroy_offset(this->local_ts
,
463 offsetof(traffic_selector_t
, destroy
));
464 this->remote_ts
->destroy_offset(this->remote_ts
,
465 offsetof(traffic_selector_t
, destroy
));
472 cmd_connection_t
*cmd_connection_create()
474 private_cmd_connection_t
*this;
482 .local_ts
= linked_list_create(),
483 .remote_ts
= linked_list_create(),
484 .profile
= PROF_UNDEF
,
487 /* always include the virtual IP in traffic selector list */
488 this->local_ts
->insert_last(this->local_ts
,
489 traffic_selector_create_dynamic(0, 0, 65535));
491 /* queue job, gets initiated as soon as we are up and running */
492 lib
->processor
->queue_job(lib
->processor
,
493 (job_t
*)callback_job_create_with_prio(
494 (callback_job_cb_t
)initiate
, this, NULL
,
495 (callback_job_cancel_t
)return_false
, JOB_PRIO_CRITICAL
));
497 return &this->public;