2 * Copyright (C) 2013 Martin Willi
3 * Copyright (C) 2013 revosec AG
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 #include "cmd_connection.h"
21 #include <utils/debug.h>
22 #include <processing/jobs/callback_job.h>
23 #include <threading/thread.h>
26 typedef enum profile_t profile_t
;
27 typedef struct private_cmd_connection_t private_cmd_connection_t
;
30 * Connection profiles we support
43 ENUM(profile_names
, PROF_V2_PUB
, PROF_V1_HYBRID
,
54 * Private data of an cmd_connection_t object.
56 struct private_cmd_connection_t
{
59 * Public cmd_connection_t interface.
61 cmd_connection_t
public;
64 * Process ID to terminate on failure
69 * List of local traffic selectors
71 linked_list_t
*local_ts
;
74 * List of remote traffic selectors
76 linked_list_t
*remote_ts
;
79 * Hostname to connect to
84 * Server identity, or NULL to use host
94 * Is a private key configured
99 * Selected connection profile
105 * Shut down application
107 static void terminate(private_cmd_connection_t
*this)
109 kill(this->pid
, SIGUSR1
);
113 * Create peer config with associated ike config
115 static peer_cfg_t
* create_peer_cfg(private_cmd_connection_t
*this)
118 peer_cfg_t
*peer_cfg
;
119 u_int16_t local_port
, remote_port
= IKEV2_UDP_PORT
;
120 ike_version_t version
= IKE_ANY
;
122 switch (this->profile
)
127 case PROF_V2_PUB_EAP
:
132 case PROF_V1_XAUTH_PSK
:
138 local_port
= charon
->socket
->get_port(charon
->socket
, FALSE
);
139 if (local_port
!= IKEV2_UDP_PORT
)
141 remote_port
= IKEV2_NATT_PORT
;
143 ike_cfg
= ike_cfg_create(version
, TRUE
, FALSE
, "0.0.0.0", FALSE
, local_port
,
144 this->host
, FALSE
, remote_port
, FRAGMENTATION_NO
, 0);
145 ike_cfg
->add_proposal(ike_cfg
, proposal_create_default(PROTO_IKE
));
146 peer_cfg
= peer_cfg_create("cmd", ike_cfg
,
147 CERT_SEND_IF_ASKED
, UNIQUE_REPLACE
, 1, /* keyingtries */
148 36000, 0, /* rekey 10h, reauth none */
149 600, 600, /* jitter, over 10min */
150 TRUE
, FALSE
, /* mobike, aggressive */
151 30, 0, /* DPD delay, timeout */
152 FALSE
, NULL
, NULL
); /* mediation */
153 peer_cfg
->add_virtual_ip(peer_cfg
, host_create_from_string("0.0.0.0", 0));
159 * Add a single auth cfg of given class to peer cfg
161 static void add_auth_cfg(private_cmd_connection_t
*this, peer_cfg_t
*peer_cfg
,
162 bool local
, auth_class_t
class)
164 identification_t
*id
;
167 auth
= auth_cfg_create();
168 auth
->add(auth
, AUTH_RULE_AUTH_CLASS
, class);
171 id
= identification_create_from_string(this->identity
);
177 id
= identification_create_from_string(this->server
);
181 id
= identification_create_from_string(this->host
);
183 auth
->add(auth
, AUTH_RULE_IDENTITY_LOOSE
, TRUE
);
185 auth
->add(auth
, AUTH_RULE_IDENTITY
, id
);
186 peer_cfg
->add_auth_cfg(peer_cfg
, auth
, local
);
190 * Attach authentication configs to peer config
192 static bool add_auth_cfgs(private_cmd_connection_t
*this, peer_cfg_t
*peer_cfg
)
194 if (this->profile
== PROF_UNDEF
)
198 this->profile
= PROF_V2_PUB
;
202 this->profile
= PROF_V2_EAP
;
205 switch (this->profile
)
208 case PROF_V2_PUB_EAP
:
213 DBG1(DBG_CFG
, "missing private key for profile %N",
214 profile_names
, this->profile
);
222 switch (this->profile
)
225 add_auth_cfg(this, peer_cfg
, TRUE
, AUTH_CLASS_PUBKEY
);
226 add_auth_cfg(this, peer_cfg
, FALSE
, AUTH_CLASS_ANY
);
229 add_auth_cfg(this, peer_cfg
, TRUE
, AUTH_CLASS_EAP
);
230 add_auth_cfg(this, peer_cfg
, FALSE
, AUTH_CLASS_ANY
);
232 case PROF_V2_PUB_EAP
:
233 add_auth_cfg(this, peer_cfg
, TRUE
, AUTH_CLASS_PUBKEY
);
234 add_auth_cfg(this, peer_cfg
, TRUE
, AUTH_CLASS_EAP
);
235 add_auth_cfg(this, peer_cfg
, FALSE
, AUTH_CLASS_ANY
);
238 add_auth_cfg(this, peer_cfg
, TRUE
, AUTH_CLASS_PUBKEY
);
239 add_auth_cfg(this, peer_cfg
, FALSE
, AUTH_CLASS_PUBKEY
);
242 add_auth_cfg(this, peer_cfg
, TRUE
, AUTH_CLASS_PUBKEY
);
243 add_auth_cfg(this, peer_cfg
, TRUE
, AUTH_CLASS_XAUTH
);
244 add_auth_cfg(this, peer_cfg
, FALSE
, AUTH_CLASS_PUBKEY
);
246 case PROF_V1_XAUTH_PSK
:
247 add_auth_cfg(this, peer_cfg
, TRUE
, AUTH_CLASS_PSK
);
248 add_auth_cfg(this, peer_cfg
, TRUE
, AUTH_CLASS_XAUTH
);
249 add_auth_cfg(this, peer_cfg
, FALSE
, AUTH_CLASS_PSK
);
252 add_auth_cfg(this, peer_cfg
, TRUE
, AUTH_CLASS_XAUTH
);
253 add_auth_cfg(this, peer_cfg
, FALSE
, AUTH_CLASS_PUBKEY
);
262 * Attach child config to peer config
264 static child_cfg_t
* create_child_cfg(private_cmd_connection_t
*this)
266 child_cfg_t
*child_cfg
;
267 traffic_selector_t
*ts
;
268 lifetime_cfg_t lifetime
= {
270 .life
= 10800 /* 3h */,
271 .rekey
= 10200 /* 2h50min */,
272 .jitter
= 300 /* 5min */
276 child_cfg
= child_cfg_create("cmd", &lifetime
,
277 NULL
, FALSE
, MODE_TUNNEL
, /* updown, hostaccess */
278 ACTION_NONE
, ACTION_NONE
, ACTION_NONE
, FALSE
,
279 0, 0, NULL
, NULL
, 0);
280 child_cfg
->add_proposal(child_cfg
, proposal_create_default(PROTO_ESP
));
281 while (this->local_ts
->remove_first(this->local_ts
, (void**)&ts
) == SUCCESS
)
283 child_cfg
->add_traffic_selector(child_cfg
, TRUE
, ts
);
285 if (this->remote_ts
->get_count(this->remote_ts
) == 0)
287 /* add a 0.0.0.0/0 TS for remote side if none given */
288 ts
= traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE
,
289 "0.0.0.0", 0, "255.255.255.255", 65535);
290 this->remote_ts
->insert_last(this->remote_ts
, ts
);
292 while (this->remote_ts
->remove_first(this->remote_ts
,
293 (void**)&ts
) == SUCCESS
)
295 child_cfg
->add_traffic_selector(child_cfg
, FALSE
, ts
);
302 * Initiate the configured connection
304 static job_requeue_t
initiate(private_cmd_connection_t
*this)
306 peer_cfg_t
*peer_cfg
;
307 child_cfg_t
*child_cfg
;
311 DBG1(DBG_CFG
, "unable to initiate, missing --host option");
313 return JOB_REQUEUE_NONE
;
317 DBG1(DBG_CFG
, "unable to initiate, missing --identity option");
319 return JOB_REQUEUE_NONE
;
322 peer_cfg
= create_peer_cfg(this);
324 if (!add_auth_cfgs(this, peer_cfg
))
326 peer_cfg
->destroy(peer_cfg
);
328 return JOB_REQUEUE_NONE
;
331 child_cfg
= create_child_cfg(this);
332 peer_cfg
->add_child_cfg(peer_cfg
, child_cfg
->get_ref(child_cfg
));
334 if (charon
->controller
->initiate(charon
->controller
, peer_cfg
, child_cfg
,
335 controller_cb_empty
, NULL
, 0) != SUCCESS
)
339 return JOB_REQUEUE_NONE
;
343 * Create a traffic selector from string, add to list
345 static void add_ts(private_cmd_connection_t
*this,
346 linked_list_t
*list
, char *string
)
348 traffic_selector_t
*ts
;
350 ts
= traffic_selector_create_from_cidr(string
, 0, 0, 65535);
353 DBG1(DBG_CFG
, "invalid traffic selector: %s", string
);
356 list
->insert_last(list
, ts
);
360 * Parse profile name identifier
362 static void set_profile(private_cmd_connection_t
*this, char *name
)
366 profile
= enum_from_name(profile_names
, name
);
369 DBG1(DBG_CFG
, "unknown connection profile: %s", name
);
372 this->profile
= profile
;
375 METHOD(cmd_connection_t
, handle
, bool,
376 private_cmd_connection_t
*this, cmd_option_type_t opt
, char *arg
)
383 case CMD_OPT_REMOTE_IDENTITY
:
386 case CMD_OPT_IDENTITY
:
387 this->identity
= arg
;
391 this->key_seen
= TRUE
;
393 case CMD_OPT_LOCAL_TS
:
394 add_ts(this, this->local_ts
, arg
);
396 case CMD_OPT_REMOTE_TS
:
397 add_ts(this, this->remote_ts
, arg
);
399 case CMD_OPT_PROFILE
:
400 set_profile(this, arg
);
408 METHOD(cmd_connection_t
, destroy
, void,
409 private_cmd_connection_t
*this)
411 this->local_ts
->destroy_offset(this->local_ts
,
412 offsetof(traffic_selector_t
, destroy
));
413 this->remote_ts
->destroy_offset(this->remote_ts
,
414 offsetof(traffic_selector_t
, destroy
));
421 cmd_connection_t
*cmd_connection_create()
423 private_cmd_connection_t
*this;
431 .local_ts
= linked_list_create(),
432 .remote_ts
= linked_list_create(),
433 .profile
= PROF_UNDEF
,
436 /* always include the virtual IP in traffic selector list */
437 this->local_ts
->insert_last(this->local_ts
,
438 traffic_selector_create_dynamic(0, 0, 65535));
440 /* queue job, gets initiated as soon as we are up and running */
441 lib
->processor
->queue_job(lib
->processor
,
442 (job_t
*)callback_job_create_with_prio(
443 (callback_job_cb_t
)initiate
, this, NULL
,
444 (callback_job_cancel_t
)return_false
, JOB_PRIO_CRITICAL
));
446 return &this->public;