]> git.proxmox.com Git - mirror_frr.git/blame - nhrpd/vici.c
Merge pull request #3239 from pguibert6WIND/ospf_virtual_link_config
[mirror_frr.git] / nhrpd / vici.c
CommitLineData
2fb975da
TT
1/* strongSwan VICI protocol implementation for NHRP
2 * Copyright (c) 2014-2015 Timo Teräs
3 *
4 * This file is free software: you may copy, redistribute and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 */
9
b45ac5f5
DL
10#ifdef HAVE_CONFIG_H
11#include "config.h"
12#endif
13
2fb975da
TT
14#include <string.h>
15#include <sys/socket.h>
16#include <sys/un.h>
17
18#include "thread.h"
19#include "zbuf.h"
20#include "log.h"
aed07011 21#include "lib_errors.h"
2fb975da 22
aed07011 23#include "nhrpd.h"
2fb975da 24#include "vici.h"
aed07011 25#include "nhrp_errors.h"
2fb975da
TT
26
27#define ERRNO_IO_RETRY(EN) (((EN) == EAGAIN) || ((EN) == EWOULDBLOCK) || ((EN) == EINTR))
28
29struct blob {
30 char *ptr;
31 int len;
32};
33
34static int blob_equal(const struct blob *b, const char *str)
35{
996c9314
LB
36 if (!b || b->len != (int)strlen(str))
37 return 0;
2fb975da
TT
38 return memcmp(b->ptr, str, b->len) == 0;
39}
40
41static int blob2buf(const struct blob *b, char *buf, size_t n)
42{
996c9314
LB
43 if (!b || b->len >= (int)n)
44 return 0;
2fb975da
TT
45 memcpy(buf, b->ptr, b->len);
46 buf[b->len] = 0;
47 return 1;
48}
49
50struct vici_conn {
51 struct thread *t_reconnect, *t_read, *t_write;
52 struct zbuf ibuf;
53 struct zbuf_queue obuf;
54 int fd;
55 uint8_t ibuf_data[VICI_MAX_MSGLEN];
56};
57
58struct vici_message_ctx {
59 const char *sections[8];
60 int nsections;
61};
62
63static int vici_reconnect(struct thread *t);
64static void vici_submit_request(struct vici_conn *vici, const char *name, ...);
65
66static void vici_zbuf_puts(struct zbuf *obuf, const char *str)
67{
68 size_t len = strlen(str);
69 zbuf_put8(obuf, len);
70 zbuf_put(obuf, str, len);
71}
72
73static void vici_connection_error(struct vici_conn *vici)
74{
75 nhrp_vc_reset();
76
77 THREAD_OFF(vici->t_read);
78 THREAD_OFF(vici->t_write);
79 zbuf_reset(&vici->ibuf);
80 zbufq_reset(&vici->obuf);
81
82 close(vici->fd);
83 vici->fd = -1;
ffa2c898 84 thread_add_timer(master, vici_reconnect, vici, 2, &vici->t_reconnect);
2fb975da
TT
85}
86
996c9314
LB
87static void vici_parse_message(struct vici_conn *vici, struct zbuf *msg,
88 void (*parser)(struct vici_message_ctx *ctx,
89 enum vici_type_t msgtype,
90 const struct blob *key,
91 const struct blob *val),
92 struct vici_message_ctx *ctx)
2fb975da
TT
93{
94 uint8_t *type;
996c9314
LB
95 struct blob key = {0};
96 struct blob val = {0};
2fb975da
TT
97
98 while ((type = zbuf_may_pull(msg, uint8_t)) != NULL) {
99 switch (*type) {
100 case VICI_SECTION_START:
101 key.len = zbuf_get8(msg);
102 key.ptr = zbuf_pulln(msg, key.len);
996c9314
LB
103 debugf(NHRP_DEBUG_VICI, "VICI: Section start '%.*s'",
104 key.len, key.ptr);
2fb975da
TT
105 parser(ctx, *type, &key, NULL);
106 ctx->nsections++;
107 break;
108 case VICI_SECTION_END:
109 debugf(NHRP_DEBUG_VICI, "VICI: Section end");
110 parser(ctx, *type, NULL, NULL);
111 ctx->nsections--;
112 break;
113 case VICI_KEY_VALUE:
114 key.len = zbuf_get8(msg);
115 key.ptr = zbuf_pulln(msg, key.len);
116 val.len = zbuf_get_be16(msg);
117 val.ptr = zbuf_pulln(msg, val.len);
996c9314
LB
118 debugf(NHRP_DEBUG_VICI, "VICI: Key '%.*s'='%.*s'",
119 key.len, key.ptr, val.len, val.ptr);
2fb975da
TT
120 parser(ctx, *type, &key, &val);
121 break;
122 case VICI_LIST_START:
123 key.len = zbuf_get8(msg);
124 key.ptr = zbuf_pulln(msg, key.len);
996c9314
LB
125 debugf(NHRP_DEBUG_VICI, "VICI: List start '%.*s'",
126 key.len, key.ptr);
2fb975da
TT
127 break;
128 case VICI_LIST_ITEM:
129 val.len = zbuf_get_be16(msg);
130 val.ptr = zbuf_pulln(msg, val.len);
996c9314
LB
131 debugf(NHRP_DEBUG_VICI, "VICI: List item: '%.*s'",
132 val.len, val.ptr);
2fb975da
TT
133 parser(ctx, *type, &key, &val);
134 break;
135 case VICI_LIST_END:
136 debugf(NHRP_DEBUG_VICI, "VICI: List end");
137 break;
138 default:
996c9314
LB
139 debugf(NHRP_DEBUG_VICI,
140 "VICI: Unsupported message component type %d",
141 *type);
2fb975da
TT
142 return;
143 }
144 }
145}
146
147struct handle_sa_ctx {
148 struct vici_message_ctx msgctx;
149 int event;
150 int child_ok;
151 int kill_ikesa;
152 uint32_t child_uniqueid, ike_uniqueid;
153 struct {
154 union sockunion host;
155 struct blob id, cert;
156 } local, remote;
157};
158
996c9314
LB
159static void parse_sa_message(struct vici_message_ctx *ctx,
160 enum vici_type_t msgtype, const struct blob *key,
161 const struct blob *val)
2fb975da 162{
996c9314
LB
163 struct handle_sa_ctx *sactx =
164 container_of(ctx, struct handle_sa_ctx, msgctx);
2fb975da
TT
165 struct nhrp_vc *vc;
166 char buf[512];
167
168 switch (msgtype) {
169 case VICI_SECTION_START:
170 if (ctx->nsections == 3) {
171 /* Begin of child-sa section, reset child vars */
172 sactx->child_uniqueid = 0;
173 sactx->child_ok = 0;
174 }
175 break;
176 case VICI_SECTION_END:
177 if (ctx->nsections == 3) {
178 /* End of child-sa section, update nhrp_vc */
179 int up = sactx->child_ok || sactx->event == 1;
180 if (up) {
996c9314
LB
181 vc = nhrp_vc_get(&sactx->local.host,
182 &sactx->remote.host, up);
2fb975da 183 if (vc) {
996c9314
LB
184 blob2buf(&sactx->local.id, vc->local.id,
185 sizeof(vc->local.id));
186 if (blob2buf(&sactx->local.cert,
187 (char *)vc->local.cert,
188 sizeof(vc->local.cert)))
189 vc->local.certlen =
190 sactx->local.cert.len;
191 blob2buf(&sactx->remote.id,
192 vc->remote.id,
193 sizeof(vc->remote.id));
194 if (blob2buf(&sactx->remote.cert,
195 (char *)vc->remote.cert,
196 sizeof(vc->remote.cert)))
197 vc->remote.certlen =
198 sactx->remote.cert.len;
199 sactx->kill_ikesa |=
200 nhrp_vc_ipsec_updown(
201 sactx->child_uniqueid,
202 vc);
2fb975da
TT
203 }
204 } else {
205 nhrp_vc_ipsec_updown(sactx->child_uniqueid, 0);
206 }
207 }
208 break;
209 default:
6b07f6e1
JB
210 if (!key)
211 break;
212
2fb975da
TT
213 switch (key->ptr[0]) {
214 case 'l':
996c9314
LB
215 if (blob_equal(key, "local-host")
216 && ctx->nsections == 1) {
2fb975da 217 if (blob2buf(val, buf, sizeof(buf)))
996c9314
LB
218 if (str2sockunion(buf,
219 &sactx->local.host)
220 < 0)
1c50c1c0
QY
221 flog_err(
222 EC_NHRP_SWAN,
223 "VICI: bad strongSwan local-host: %s",
224 buf);
996c9314
LB
225 } else if (blob_equal(key, "local-id")
226 && ctx->nsections == 1) {
2fb975da 227 sactx->local.id = *val;
996c9314
LB
228 } else if (blob_equal(key, "local-cert-data")
229 && ctx->nsections == 1) {
2fb975da
TT
230 sactx->local.cert = *val;
231 }
232 break;
233 case 'r':
996c9314
LB
234 if (blob_equal(key, "remote-host")
235 && ctx->nsections == 1) {
2fb975da 236 if (blob2buf(val, buf, sizeof(buf)))
996c9314
LB
237 if (str2sockunion(buf,
238 &sactx->remote.host)
239 < 0)
1c50c1c0
QY
240 flog_err(
241 EC_NHRP_SWAN,
242 "VICI: bad strongSwan remote-host: %s",
243 buf);
996c9314
LB
244 } else if (blob_equal(key, "remote-id")
245 && ctx->nsections == 1) {
2fb975da 246 sactx->remote.id = *val;
996c9314
LB
247 } else if (blob_equal(key, "remote-cert-data")
248 && ctx->nsections == 1) {
2fb975da
TT
249 sactx->remote.cert = *val;
250 }
251 break;
252 case 'u':
996c9314
LB
253 if (blob_equal(key, "uniqueid")
254 && blob2buf(val, buf, sizeof(buf))) {
2fb975da 255 if (ctx->nsections == 3)
996c9314
LB
256 sactx->child_uniqueid =
257 strtoul(buf, NULL, 0);
2fb975da 258 else if (ctx->nsections == 1)
996c9314
LB
259 sactx->ike_uniqueid =
260 strtoul(buf, NULL, 0);
2fb975da
TT
261 }
262 break;
263 case 's':
264 if (blob_equal(key, "state") && ctx->nsections == 3) {
265 sactx->child_ok =
996c9314
LB
266 (sactx->event == 0
267 && (blob_equal(val, "INSTALLED")
268 || blob_equal(val, "REKEYED")));
2fb975da
TT
269 }
270 break;
271 }
272 break;
273 }
274}
275
996c9314
LB
276static void parse_cmd_response(struct vici_message_ctx *ctx,
277 enum vici_type_t msgtype, const struct blob *key,
278 const struct blob *val)
d139786a
TT
279{
280 char buf[512];
281
282 switch (msgtype) {
283 case VICI_KEY_VALUE:
996c9314
LB
284 if (blob_equal(key, "errmsg")
285 && blob2buf(val, buf, sizeof(buf)))
2b84a521 286 flog_err(EC_NHRP_SWAN, "VICI: strongSwan: %s", buf);
d139786a
TT
287 break;
288 default:
289 break;
290 }
291}
292
2fb975da
TT
293static void vici_recv_sa(struct vici_conn *vici, struct zbuf *msg, int event)
294{
295 char buf[32];
296 struct handle_sa_ctx ctx = {
297 .event = event,
0a939f4f 298 .msgctx.nsections = 0
2fb975da
TT
299 };
300
301 vici_parse_message(vici, msg, parse_sa_message, &ctx.msgctx);
302
303 if (ctx.kill_ikesa && ctx.ike_uniqueid) {
996c9314
LB
304 debugf(NHRP_DEBUG_COMMON, "VICI: Deleting IKE_SA %u",
305 ctx.ike_uniqueid);
2fb975da 306 snprintf(buf, sizeof buf, "%u", ctx.ike_uniqueid);
996c9314
LB
307 vici_submit_request(vici, "terminate", VICI_KEY_VALUE, "ike-id",
308 strlen(buf), buf, VICI_END);
2fb975da
TT
309 }
310}
311
312static void vici_recv_message(struct vici_conn *vici, struct zbuf *msg)
313{
314 uint32_t msglen;
315 uint8_t msgtype;
316 struct blob name;
7ea5df54 317 struct vici_message_ctx ctx = { .nsections = 0 };
2fb975da
TT
318
319 msglen = zbuf_get_be32(msg);
320 msgtype = zbuf_get8(msg);
321 debugf(NHRP_DEBUG_VICI, "VICI: Message %d, %d bytes", msgtype, msglen);
322
323 switch (msgtype) {
324 case VICI_EVENT:
325 name.len = zbuf_get8(msg);
326 name.ptr = zbuf_pulln(msg, name.len);
327
996c9314
LB
328 debugf(NHRP_DEBUG_VICI, "VICI: Event '%.*s'", name.len,
329 name.ptr);
330 if (blob_equal(&name, "list-sa")
331 || blob_equal(&name, "child-updown")
332 || blob_equal(&name, "child-rekey"))
2fb975da 333 vici_recv_sa(vici, msg, 0);
996c9314
LB
334 else if (blob_equal(&name, "child-state-installed")
335 || blob_equal(&name, "child-state-rekeyed"))
2fb975da
TT
336 vici_recv_sa(vici, msg, 1);
337 else if (blob_equal(&name, "child-state-destroying"))
338 vici_recv_sa(vici, msg, 2);
339 break;
d139786a 340 case VICI_CMD_RESPONSE:
6c8ca260 341 vici_parse_message(vici, msg, parse_cmd_response, &ctx);
d139786a 342 break;
2fb975da 343 case VICI_EVENT_UNKNOWN:
d139786a 344 case VICI_CMD_UNKNOWN:
1c50c1c0
QY
345 flog_err(
346 EC_NHRP_SWAN,
996c9314 347 "VICI: StrongSwan does not support mandatory events (unpatched?)");
2fb975da
TT
348 break;
349 case VICI_EVENT_CONFIRM:
2fb975da
TT
350 break;
351 default:
352 zlog_notice("VICI: Unrecognized message type %d", msgtype);
353 break;
354 }
355}
356
357static int vici_read(struct thread *t)
358{
359 struct vici_conn *vici = THREAD_ARG(t);
360 struct zbuf *ibuf = &vici->ibuf;
361 struct zbuf pktbuf;
362
363 vici->t_read = NULL;
996c9314 364 if (zbuf_read(ibuf, vici->fd, (size_t)-1) < 0) {
2fb975da
TT
365 vici_connection_error(vici);
366 return 0;
367 }
368
369 /* Process all messages in buffer */
370 do {
371 uint32_t *hdrlen = zbuf_may_pull(ibuf, uint32_t);
372 if (!hdrlen)
373 break;
374 if (!zbuf_may_pulln(ibuf, ntohl(*hdrlen))) {
375 zbuf_reset_head(ibuf, hdrlen);
376 break;
377 }
378
379 /* Handle packet */
996c9314
LB
380 zbuf_init(&pktbuf, hdrlen, htonl(*hdrlen) + 4,
381 htonl(*hdrlen) + 4);
2fb975da
TT
382 vici_recv_message(vici, &pktbuf);
383 } while (1);
384
ffa2c898 385 thread_add_read(master, vici_read, vici, vici->fd, &vici->t_read);
2fb975da
TT
386 return 0;
387}
388
389static int vici_write(struct thread *t)
390{
391 struct vici_conn *vici = THREAD_ARG(t);
392 int r;
393
394 vici->t_write = NULL;
395 r = zbufq_write(&vici->obuf, vici->fd);
396 if (r > 0) {
ffa2c898
QY
397 thread_add_write(master, vici_write, vici, vici->fd,
398 &vici->t_write);
2fb975da
TT
399 } else if (r < 0) {
400 vici_connection_error(vici);
401 }
402
403 return 0;
404}
405
406static void vici_submit(struct vici_conn *vici, struct zbuf *obuf)
407{
408 if (vici->fd < 0) {
409 zbuf_free(obuf);
410 return;
411 }
412
413 zbufq_queue(&vici->obuf, obuf);
ffa2c898 414 thread_add_write(master, vici_write, vici, vici->fd, &vici->t_write);
2fb975da
TT
415}
416
417static void vici_submit_request(struct vici_conn *vici, const char *name, ...)
418{
419 struct zbuf *obuf;
420 uint32_t *hdrlen;
421 va_list va;
422 size_t len;
423 int type;
424
425 obuf = zbuf_alloc(256);
996c9314
LB
426 if (!obuf)
427 return;
2fb975da
TT
428
429 hdrlen = zbuf_push(obuf, uint32_t);
430 zbuf_put8(obuf, VICI_CMD_REQUEST);
431 vici_zbuf_puts(obuf, name);
432
433 va_start(va, name);
434 for (type = va_arg(va, int); type != VICI_END; type = va_arg(va, int)) {
435 zbuf_put8(obuf, type);
436 switch (type) {
437 case VICI_KEY_VALUE:
438 vici_zbuf_puts(obuf, va_arg(va, const char *));
439 len = va_arg(va, size_t);
440 zbuf_put_be16(obuf, len);
441 zbuf_put(obuf, va_arg(va, void *), len);
442 break;
2fb975da
TT
443 default:
444 break;
445 }
446 }
447 va_end(va);
448 *hdrlen = htonl(zbuf_used(obuf) - 4);
449 vici_submit(vici, obuf);
450}
451
452static void vici_register_event(struct vici_conn *vici, const char *name)
453{
454 struct zbuf *obuf;
455 uint32_t *hdrlen;
456 uint8_t namelen;
457
458 namelen = strlen(name);
459 obuf = zbuf_alloc(4 + 1 + 1 + namelen);
996c9314
LB
460 if (!obuf)
461 return;
2fb975da
TT
462
463 hdrlen = zbuf_push(obuf, uint32_t);
464 zbuf_put8(obuf, VICI_EVENT_REGISTER);
465 zbuf_put8(obuf, namelen);
466 zbuf_put(obuf, name, namelen);
467 *hdrlen = htonl(zbuf_used(obuf) - 4);
468
469 vici_submit(vici, obuf);
470}
471
472static int vici_reconnect(struct thread *t)
473{
474 struct vici_conn *vici = THREAD_ARG(t);
475 int fd;
476
477 vici->t_reconnect = NULL;
996c9314
LB
478 if (vici->fd >= 0)
479 return 0;
2fb975da
TT
480
481 fd = sock_open_unix("/var/run/charon.vici");
482 if (fd < 0) {
996c9314
LB
483 debugf(NHRP_DEBUG_VICI,
484 "%s: failure connecting VICI socket: %s",
485 __PRETTY_FUNCTION__, strerror(errno));
ffa2c898
QY
486 thread_add_timer(master, vici_reconnect, vici, 2,
487 &vici->t_reconnect);
2fb975da
TT
488 return 0;
489 }
490
491 debugf(NHRP_DEBUG_COMMON, "VICI: Connected");
492 vici->fd = fd;
ffa2c898 493 thread_add_read(master, vici_read, vici, vici->fd, &vici->t_read);
2fb975da
TT
494
495 /* Send event subscribtions */
996c9314
LB
496 // vici_register_event(vici, "child-updown");
497 // vici_register_event(vici, "child-rekey");
2fb975da
TT
498 vici_register_event(vici, "child-state-installed");
499 vici_register_event(vici, "child-state-rekeyed");
500 vici_register_event(vici, "child-state-destroying");
501 vici_register_event(vici, "list-sa");
502 vici_submit_request(vici, "list-sas", VICI_END);
503
504 return 0;
505}
506
507static struct vici_conn vici_connection;
508
509void vici_init(void)
510{
511 struct vici_conn *vici = &vici_connection;
512
513 vici->fd = -1;
514 zbuf_init(&vici->ibuf, vici->ibuf_data, sizeof(vici->ibuf_data), 0);
515 zbufq_init(&vici->obuf);
ffa2c898
QY
516 thread_add_timer_msec(master, vici_reconnect, vici, 10,
517 &vici->t_reconnect);
2fb975da
TT
518}
519
520void vici_terminate(void)
521{
522}
523
996c9314
LB
524void vici_request_vc(const char *profile, union sockunion *src,
525 union sockunion *dst, int prio)
2fb975da
TT
526{
527 struct vici_conn *vici = &vici_connection;
528 char buf[2][SU_ADDRSTRLEN];
529
530 sockunion2str(src, buf[0], sizeof buf[0]);
531 sockunion2str(dst, buf[1], sizeof buf[1]);
532
996c9314
LB
533 vici_submit_request(vici, "initiate", VICI_KEY_VALUE, "child",
534 strlen(profile), profile, VICI_KEY_VALUE, "timeout",
535 (size_t)2, "-1", VICI_KEY_VALUE, "async", (size_t)1,
536 "1", VICI_KEY_VALUE, "init-limits", (size_t)1,
537 prio ? "0" : "1", VICI_KEY_VALUE, "my-host",
538 strlen(buf[0]), buf[0], VICI_KEY_VALUE,
539 "other-host", strlen(buf[1]), buf[1], VICI_END);
2fb975da
TT
540}
541
542int sock_open_unix(const char *path)
543{
544 int ret, fd;
545 struct sockaddr_un addr;
546
547 fd = socket(AF_UNIX, SOCK_STREAM, 0);
548 if (fd < 0)
549 return -1;
550
996c9314 551 memset(&addr, 0, sizeof(struct sockaddr_un));
2fb975da 552 addr.sun_family = AF_UNIX;
6c8ca260 553 strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
2fb975da 554
996c9314
LB
555 ret = connect(fd, (struct sockaddr *)&addr,
556 sizeof(addr.sun_family) + strlen(addr.sun_path));
2fb975da
TT
557 if (ret < 0) {
558 close(fd);
559 return -1;
560 }
561
6c8ca260
JB
562 ret = fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
563 if (ret < 0) {
564 close(fd);
565 return -1;
566 }
2fb975da
TT
567
568 return fd;
569}