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