1 /* whack communicating routines
2 * Copyright (C) 1997 Angelos D. Keromytis.
3 * Copyright (C) 1998-2001 D. Hugh Redelmeier.
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
15 * RCSID $Id: kernel_comm.c,v 1.69 2002/03/22 23:38:27 dhr Exp $
23 #include <sys/types.h>
24 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
29 #include <arpa/nameser.h> /* missing from <resolv.h> on old systems */
33 #include "constants.h"
37 #include "connections.h" /* needs id.h */
38 #include "whack.h" /* needs connections.h */
40 #include "demux.h" /* needs packet.h */
42 #include "ipsec_doi.h" /* needs demux.h and state.h */
44 #include "kernel_comm.h"
47 #include "preshared.h"
48 #include "adns.h" /* needs <resolv.h> */
49 #include "dnskey.h" /* needs preshared.h and adns.h */
51 #include "kernel_alg.h"
53 #ifndef NO_DB_OPS_STATS
57 /* helper variables and function to decode strings from whack message */
65 char *end = memchr(next_str, '\0', str_roof - next_str);
69 return FALSE; /* fishy: no end found */
73 *p = next_str == end? NULL : next_str;
79 /* bits loading keys from asynchronous DNS */
81 struct key_add_continuation {
82 struct adns_continuation ac;
87 key_add_ugh(const struct id *keyid, err_t ugh)
89 char name[IDTOA_BUF]; /* longer IDs will be truncated in message */
91 (void)idtoa(keyid, name, sizeof(name));
93 , "failure to fetch key for %s from DNS: %s", name, ugh);
97 key_add_continue(struct adns_continuation *ac, err_t ugh)
99 struct key_add_continuation *kc = (void *) ac;
101 whack_log_fd = kc->whack_fd;
104 key_add_ugh(&ac->id, ugh);
108 remember_public_keys(&keys_from_dns);
110 close_any(whack_log_fd);
113 /* Handle a kernel request. Supposedly, there's a message in
114 * the kernelsock socket.
117 whack_handle(int whackctlfd)
119 struct whack_message msg;
120 struct sockaddr_un whackaddr;
121 int whackaddrlen = sizeof(whackaddr);
122 int whackfd = accept(whackctlfd, (struct sockaddr *)&whackaddr, &whackaddrlen);
127 log_errno((e, "accept() failed in whack_handle()"));
130 n = read(whackfd, &msg, sizeof(msg));
133 log_errno((e, "read() failed in whack_handle()"));
138 whack_log_fd = whackfd;
140 /* sanity check message */
144 next_str = msg.string;
145 str_roof = (char *)&msg + n;
147 if (next_str > str_roof)
149 ugh = builddiag("truncated message from whack: got %d bytes; expected %d. Message ignored."
150 , n, (int) sizeof(msg));
152 else if (msg.magic != WHACK_MAGIC)
154 ugh = builddiag("message from whack has bad magic %d; should be %d; probably wrong version. Message ignored"
155 , msg.magic, WHACK_MAGIC);
157 else if (!unpack_str(&msg.name) /* string 1 */
158 || !unpack_str(&msg.left.id) /* string 2 */
159 || !unpack_str(&msg.left.cert) /* string 3 */
160 || !unpack_str(&msg.left.updown) /* string 4 */
162 || !unpack_str(&msg.left.virt)
164 || !unpack_str(&msg.right.id) /* string 5 */
165 || !unpack_str(&msg.right.cert) /* string 6 */
166 || !unpack_str(&msg.right.updown) /* string 7 */
168 || !unpack_str(&msg.right.virt)
170 || !unpack_str(&msg.keyid) /* string 8 */
171 || !unpack_str(&msg.ike) /* string 9 */
172 || !unpack_str(&msg.esp) /* string 10 */
173 || !unpack_str(&msg.dnshostname) /* string 11 */
174 || str_roof - next_str != (ptrdiff_t)msg.keyval.len) /* check chunk */
176 ugh = "message from whack contains bad string";
180 msg.keyval.ptr = next_str; /* grab chunk */
185 loglog(RC_BADWHACKMESSAGE, "%s", ugh);
186 whack_log_fd = NULL_FD;
192 if (msg.whack_options)
195 if (msg.name == NULL)
197 /* we do a two-step so that if either old or new would
198 * cause the message to print, it will be printed.
200 cur_debugging |= msg.debugging;
202 , DBG_log("base debugging = %s"
203 , bitnamesof(debug_bit_names, msg.debugging)));
204 cur_debugging = base_debugging = msg.debugging;
206 else if (!msg.whack_connection)
208 struct connection *c = con_by_name(msg.name, TRUE);
212 c->extra_debugging = msg.debugging;
214 , DBG_log("\"%s\" extra_debugging = %s"
216 , bitnamesof(debug_bit_names, c->extra_debugging)));
222 /* Deleting combined with adding a connection works as replace.
223 * To make this more useful, in only this combination,
224 * delete will silently ignore the lack of the connection.
226 if (msg.whack_delete)
228 struct connection *c = con_by_name(msg.name, !msg.whack_connection);
230 /* note: this is a "while" because road warrior
231 * leads to multiple connections with the same name.
233 for (; c != NULL; c = con_by_name(msg.name, FALSE))
234 delete_connection(c);
237 if (msg.whack_deletestate)
239 struct state *st = state_with_serialno(msg.whack_deletestateno);
243 loglog(RC_UNKNOWN_NAME, "no state #%lu to delete"
244 , msg.whack_deletestateno);
252 if (msg.whack_connection)
253 add_connection(&msg);
255 /* process "listen" before any operation that could require it */
256 if (msg.whack_listen)
258 log("listening for IKE messages");
261 load_preshared_secrets();
263 if (msg.whack_unlisten)
265 log("no longer listening for IKE messages");
269 if (msg.whack_reread & REREAD_SECRETS)
271 load_preshared_secrets();
274 if (msg.whack_reread & REREAD_MYCERT)
279 if (msg.whack_reread & REREAD_CACERTS)
284 if (msg.whack_reread & REREAD_CRLS)
289 if (msg.whack_list & LIST_PUBKEYS)
291 list_public_keys(msg.whack_utc);
294 if (msg.whack_list & LIST_CERTS)
296 list_certs(msg.whack_utc);
299 if (msg.whack_list & LIST_CACERTS)
301 list_cacerts(msg.whack_utc);
304 if (msg.whack_list & LIST_CRLS)
306 list_crls(msg.whack_utc);
311 /* add a public key */
313 err_t ugh = atoid(msg.keyid, &keyid);
317 loglog(RC_BADID, "bad --keyid \"%s\": %s", msg.keyid, ugh);
321 if (!msg.whack_addkey)
322 delete_public_keys(&keyid, msg.pubkey_alg);
324 if (msg.keyval.len == 0)
326 struct key_add_continuation *kc
327 = alloc_thing(struct key_add_continuation
328 , "key add continuation");
329 int wfd = dup_any(whackfd);
332 ugh = start_adns_query(&keyid
340 key_add_ugh(&keyid, ugh);
346 ugh = add_public_key(&keyid, DAL_LOCAL, msg.pubkey_alg
347 , &msg.keyval, &pubkeys);
349 loglog(RC_LOG_SERIOUS, "%s", ugh);
357 whack_log(RC_DEAF, "need --listen before --route");
360 struct connection *c = con_by_name(msg.name, TRUE);
364 set_cur_connection(c);
367 , "we have no ipsecN interface for either end of this connection");
368 else if (!trap_connection(c))
369 whack_log(RC_ROUTE, "could not route");
370 reset_cur_connection();
375 if (msg.whack_unroute)
377 struct connection *c = con_by_name(msg.name, TRUE);
381 set_cur_connection(c);
382 if (c->routing >= RT_ROUTED_TUNNEL)
383 whack_log(RC_RTBUSY, "cannot unroute: route busy");
385 unroute_connection(c);
386 reset_cur_connection();
390 if (msg.whack_initiate)
393 whack_log(RC_DEAF, "need --listen before --initiate");
395 initiate_connection(msg.name
396 , msg.whack_async? NULL_FD : dup_any(whackfd));
399 if (msg.whack_oppo_initiate)
402 whack_log(RC_DEAF, "need --listen before opportunistic initiation");
404 initiate_opportunistic(&msg.oppo_my_client, &msg.oppo_peer_client
406 , msg.whack_async? NULL_FD : dup_any(whackfd));
409 if (msg.whack_terminate)
410 terminate_connection(msg.name);
412 if (msg.whack_status)
414 show_ifaces_status();
415 whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */
416 #ifndef NO_KERNEL_ALG
417 kernel_alg_show_status();
418 whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */
421 ike_alg_show_status();
422 whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */
424 #ifndef NO_DB_OPS_STATS
425 db_ops_show_status();
426 whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */
428 show_connections_status();
429 whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */
430 show_states_status();
433 if (msg.whack_shutdown)
435 log("shutting down");
436 exit_pluto(0); /* delete lock and leave, with 0 status */
439 whack_log_fd = NULL_FD;