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
46 ENUM(profile_names
, PROF_V2_PUB
, PROF_V1_HYBRID
,
57 * Private data of an cmd_connection_t object.
59 struct private_cmd_connection_t
{
62 * Public cmd_connection_t interface.
64 cmd_connection_t
public;
67 * Process ID to terminate on failure
72 * List of local traffic selectors
74 linked_list_t
*local_ts
;
77 * List of remote traffic selectors
79 linked_list_t
*remote_ts
;
82 * Hostname to connect to
87 * Server identity, or NULL to use host
97 * Is a private key configured
102 * Selected connection profile
108 * Shut down application
110 static void terminate(private_cmd_connection_t
*this)
112 kill(this->pid
, SIGUSR1
);
116 * Create peer config with associated ike config
118 static peer_cfg_t
* create_peer_cfg(private_cmd_connection_t
*this)
121 peer_cfg_t
*peer_cfg
;
122 u_int16_t local_port
, remote_port
= IKEV2_UDP_PORT
;
123 ike_version_t version
= IKE_ANY
;
125 switch (this->profile
)
130 case PROF_V2_PUB_EAP
:
135 case PROF_V1_XAUTH_PSK
:
141 local_port
= charon
->socket
->get_port(charon
->socket
, FALSE
);
142 if (local_port
!= IKEV2_UDP_PORT
)
144 remote_port
= IKEV2_NATT_PORT
;
146 ike_cfg
= ike_cfg_create(version
, TRUE
, FALSE
, "0.0.0.0", FALSE
, local_port
,
147 this->host
, FALSE
, remote_port
, FRAGMENTATION_NO
, 0);
148 ike_cfg
->add_proposal(ike_cfg
, proposal_create_default(PROTO_IKE
));
149 peer_cfg
= peer_cfg_create("cmd", ike_cfg
,
150 CERT_SEND_IF_ASKED
, UNIQUE_REPLACE
, 1, /* keyingtries */
151 36000, 0, /* rekey 10h, reauth none */
152 600, 600, /* jitter, over 10min */
153 TRUE
, FALSE
, /* mobike, aggressive */
154 30, 0, /* DPD delay, timeout */
155 FALSE
, NULL
, NULL
); /* mediation */
156 peer_cfg
->add_virtual_ip(peer_cfg
, host_create_from_string("0.0.0.0", 0));
162 * Add a single auth cfg of given class to peer cfg
164 static void add_auth_cfg(private_cmd_connection_t
*this, peer_cfg_t
*peer_cfg
,
165 bool local
, auth_class_t
class)
167 identification_t
*id
;
170 auth
= auth_cfg_create();
171 auth
->add(auth
, AUTH_RULE_AUTH_CLASS
, class);
174 id
= identification_create_from_string(this->identity
);
180 id
= identification_create_from_string(this->server
);
184 id
= identification_create_from_string(this->host
);
186 auth
->add(auth
, AUTH_RULE_IDENTITY_LOOSE
, TRUE
);
188 auth
->add(auth
, AUTH_RULE_IDENTITY
, id
);
189 peer_cfg
->add_auth_cfg(peer_cfg
, auth
, local
);
193 * Attach authentication configs to peer config
195 static bool add_auth_cfgs(private_cmd_connection_t
*this, peer_cfg_t
*peer_cfg
)
197 if (this->profile
== PROF_UNDEF
)
201 this->profile
= PROF_V2_PUB
;
205 this->profile
= PROF_V2_EAP
;
208 switch (this->profile
)
211 case PROF_V2_PUB_EAP
:
216 DBG1(DBG_CFG
, "missing private key for profile %N",
217 profile_names
, this->profile
);
225 switch (this->profile
)
228 add_auth_cfg(this, peer_cfg
, TRUE
, AUTH_CLASS_PUBKEY
);
229 add_auth_cfg(this, peer_cfg
, FALSE
, AUTH_CLASS_ANY
);
232 add_auth_cfg(this, peer_cfg
, TRUE
, AUTH_CLASS_EAP
);
233 add_auth_cfg(this, peer_cfg
, FALSE
, AUTH_CLASS_ANY
);
235 case PROF_V2_PUB_EAP
:
236 add_auth_cfg(this, peer_cfg
, TRUE
, AUTH_CLASS_PUBKEY
);
237 add_auth_cfg(this, peer_cfg
, TRUE
, AUTH_CLASS_EAP
);
238 add_auth_cfg(this, peer_cfg
, FALSE
, AUTH_CLASS_ANY
);
241 add_auth_cfg(this, peer_cfg
, TRUE
, AUTH_CLASS_PUBKEY
);
242 add_auth_cfg(this, peer_cfg
, FALSE
, AUTH_CLASS_PUBKEY
);
245 add_auth_cfg(this, peer_cfg
, TRUE
, AUTH_CLASS_PUBKEY
);
246 add_auth_cfg(this, peer_cfg
, TRUE
, AUTH_CLASS_XAUTH
);
247 add_auth_cfg(this, peer_cfg
, FALSE
, AUTH_CLASS_PUBKEY
);
249 case PROF_V1_XAUTH_PSK
:
250 add_auth_cfg(this, peer_cfg
, TRUE
, AUTH_CLASS_PSK
);
251 add_auth_cfg(this, peer_cfg
, TRUE
, AUTH_CLASS_XAUTH
);
252 add_auth_cfg(this, peer_cfg
, FALSE
, AUTH_CLASS_PSK
);
255 add_auth_cfg(this, peer_cfg
, TRUE
, AUTH_CLASS_XAUTH
);
256 add_auth_cfg(this, peer_cfg
, FALSE
, AUTH_CLASS_PUBKEY
);
265 * Attach child config to peer config
267 static child_cfg_t
* create_child_cfg(private_cmd_connection_t
*this)
269 child_cfg_t
*child_cfg
;
270 traffic_selector_t
*ts
;
271 lifetime_cfg_t lifetime
= {
273 .life
= 10800 /* 3h */,
274 .rekey
= 10200 /* 2h50min */,
275 .jitter
= 300 /* 5min */
279 child_cfg
= child_cfg_create("cmd", &lifetime
,
280 NULL
, FALSE
, MODE_TUNNEL
, /* updown, hostaccess */
281 ACTION_NONE
, ACTION_NONE
, ACTION_NONE
, FALSE
,
282 0, 0, NULL
, NULL
, 0);
283 child_cfg
->add_proposal(child_cfg
, proposal_create_default(PROTO_ESP
));
284 while (this->local_ts
->remove_first(this->local_ts
, (void**)&ts
) == SUCCESS
)
286 child_cfg
->add_traffic_selector(child_cfg
, TRUE
, ts
);
288 if (this->remote_ts
->get_count(this->remote_ts
) == 0)
290 /* add a 0.0.0.0/0 TS for remote side if none given */
291 ts
= traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE
,
292 "0.0.0.0", 0, "255.255.255.255", 65535);
293 this->remote_ts
->insert_last(this->remote_ts
, ts
);
295 while (this->remote_ts
->remove_first(this->remote_ts
,
296 (void**)&ts
) == SUCCESS
)
298 child_cfg
->add_traffic_selector(child_cfg
, FALSE
, ts
);
305 * Initiate the configured connection
307 static job_requeue_t
initiate(private_cmd_connection_t
*this)
309 peer_cfg_t
*peer_cfg
;
310 child_cfg_t
*child_cfg
;
314 DBG1(DBG_CFG
, "unable to initiate, missing --host option");
316 return JOB_REQUEUE_NONE
;
320 DBG1(DBG_CFG
, "unable to initiate, missing --identity option");
322 return JOB_REQUEUE_NONE
;
325 peer_cfg
= create_peer_cfg(this);
327 if (!add_auth_cfgs(this, peer_cfg
))
329 peer_cfg
->destroy(peer_cfg
);
331 return JOB_REQUEUE_NONE
;
334 child_cfg
= create_child_cfg(this);
335 peer_cfg
->add_child_cfg(peer_cfg
, child_cfg
->get_ref(child_cfg
));
337 if (charon
->controller
->initiate(charon
->controller
, peer_cfg
, child_cfg
,
338 controller_cb_empty
, NULL
, 0) != SUCCESS
)
342 return JOB_REQUEUE_NONE
;
346 * Create a traffic selector from string, add to list
348 static void add_ts(private_cmd_connection_t
*this,
349 linked_list_t
*list
, char *string
)
351 traffic_selector_t
*ts
;
353 ts
= traffic_selector_create_from_cidr(string
, 0, 0, 65535);
356 DBG1(DBG_CFG
, "invalid traffic selector: %s", string
);
359 list
->insert_last(list
, ts
);
363 * Parse profile name identifier
365 static void set_profile(private_cmd_connection_t
*this, char *name
)
369 profile
= enum_from_name(profile_names
, name
);
372 DBG1(DBG_CFG
, "unknown connection profile: %s", name
);
375 this->profile
= profile
;
378 METHOD(cmd_connection_t
, handle
, bool,
379 private_cmd_connection_t
*this, cmd_option_type_t opt
, char *arg
)
386 case CMD_OPT_REMOTE_IDENTITY
:
389 case CMD_OPT_IDENTITY
:
390 this->identity
= arg
;
394 this->key_seen
= TRUE
;
396 case CMD_OPT_LOCAL_TS
:
397 add_ts(this, this->local_ts
, arg
);
399 case CMD_OPT_REMOTE_TS
:
400 add_ts(this, this->remote_ts
, arg
);
402 case CMD_OPT_PROFILE
:
403 set_profile(this, arg
);
411 METHOD(cmd_connection_t
, destroy
, void,
412 private_cmd_connection_t
*this)
414 this->local_ts
->destroy_offset(this->local_ts
,
415 offsetof(traffic_selector_t
, destroy
));
416 this->remote_ts
->destroy_offset(this->remote_ts
,
417 offsetof(traffic_selector_t
, destroy
));
424 cmd_connection_t
*cmd_connection_create()
426 private_cmd_connection_t
*this;
434 .local_ts
= linked_list_create(),
435 .remote_ts
= linked_list_create(),
436 .profile
= PROF_UNDEF
,
439 /* always include the virtual IP in traffic selector list */
440 this->local_ts
->insert_last(this->local_ts
,
441 traffic_selector_create_dynamic(0, 0, 65535));
443 /* queue job, gets initiated as soon as we are up and running */
444 lib
->processor
->queue_job(lib
->processor
,
445 (job_t
*)callback_job_create_with_prio(
446 (callback_job_cb_t
)initiate
, this, NULL
,
447 (callback_job_cancel_t
)return_false
, JOB_PRIO_CRITICAL
));
449 return &this->public;