1 /* strongSwan VICI protocol implementation for NHRP
2 * Copyright (c) 2014-2015 Timo Teräs
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.
11 #include <sys/socket.h>
21 #define ERRNO_IO_RETRY(EN) (((EN) == EAGAIN) || ((EN) == EWOULDBLOCK) || ((EN) == EINTR))
28 static int blob_equal(const struct blob
*b
, const char *str
)
30 if (!b
|| b
->len
!= (int)strlen(str
))
32 return memcmp(b
->ptr
, str
, b
->len
) == 0;
35 static int blob2buf(const struct blob
*b
, char *buf
, size_t n
)
37 if (!b
|| b
->len
>= (int)n
)
39 memcpy(buf
, b
->ptr
, b
->len
);
45 struct thread
*t_reconnect
, *t_read
, *t_write
;
47 struct zbuf_queue obuf
;
49 uint8_t ibuf_data
[VICI_MAX_MSGLEN
];
52 struct vici_message_ctx
{
53 const char *sections
[8];
57 static int vici_reconnect(struct thread
*t
);
58 static void vici_submit_request(struct vici_conn
*vici
, const char *name
, ...);
60 static void vici_zbuf_puts(struct zbuf
*obuf
, const char *str
)
62 size_t len
= strlen(str
);
64 zbuf_put(obuf
, str
, len
);
67 static void vici_connection_error(struct vici_conn
*vici
)
71 THREAD_OFF(vici
->t_read
);
72 THREAD_OFF(vici
->t_write
);
73 zbuf_reset(&vici
->ibuf
);
74 zbufq_reset(&vici
->obuf
);
78 thread_add_timer(master
, vici_reconnect
, vici
, 2, &vici
->t_reconnect
);
81 static void vici_parse_message(struct vici_conn
*vici
, struct zbuf
*msg
,
82 void (*parser
)(struct vici_message_ctx
*ctx
,
83 enum vici_type_t msgtype
,
84 const struct blob
*key
,
85 const struct blob
*val
),
86 struct vici_message_ctx
*ctx
)
89 struct blob key
= {0};
90 struct blob val
= {0};
92 while ((type
= zbuf_may_pull(msg
, uint8_t)) != NULL
) {
94 case VICI_SECTION_START
:
95 key
.len
= zbuf_get8(msg
);
96 key
.ptr
= zbuf_pulln(msg
, key
.len
);
97 debugf(NHRP_DEBUG_VICI
, "VICI: Section start '%.*s'",
99 parser(ctx
, *type
, &key
, NULL
);
102 case VICI_SECTION_END
:
103 debugf(NHRP_DEBUG_VICI
, "VICI: Section end");
104 parser(ctx
, *type
, NULL
, NULL
);
108 key
.len
= zbuf_get8(msg
);
109 key
.ptr
= zbuf_pulln(msg
, key
.len
);
110 val
.len
= zbuf_get_be16(msg
);
111 val
.ptr
= zbuf_pulln(msg
, val
.len
);
112 debugf(NHRP_DEBUG_VICI
, "VICI: Key '%.*s'='%.*s'",
113 key
.len
, key
.ptr
, val
.len
, val
.ptr
);
114 parser(ctx
, *type
, &key
, &val
);
116 case VICI_LIST_START
:
117 key
.len
= zbuf_get8(msg
);
118 key
.ptr
= zbuf_pulln(msg
, key
.len
);
119 debugf(NHRP_DEBUG_VICI
, "VICI: List start '%.*s'",
123 val
.len
= zbuf_get_be16(msg
);
124 val
.ptr
= zbuf_pulln(msg
, val
.len
);
125 debugf(NHRP_DEBUG_VICI
, "VICI: List item: '%.*s'",
127 parser(ctx
, *type
, &key
, &val
);
130 debugf(NHRP_DEBUG_VICI
, "VICI: List end");
133 debugf(NHRP_DEBUG_VICI
,
134 "VICI: Unsupported message component type %d",
141 struct handle_sa_ctx
{
142 struct vici_message_ctx msgctx
;
146 uint32_t child_uniqueid
, ike_uniqueid
;
148 union sockunion host
;
149 struct blob id
, cert
;
153 static void parse_sa_message(struct vici_message_ctx
*ctx
,
154 enum vici_type_t msgtype
, const struct blob
*key
,
155 const struct blob
*val
)
157 struct handle_sa_ctx
*sactx
=
158 container_of(ctx
, struct handle_sa_ctx
, msgctx
);
163 case VICI_SECTION_START
:
164 if (ctx
->nsections
== 3) {
165 /* Begin of child-sa section, reset child vars */
166 sactx
->child_uniqueid
= 0;
170 case VICI_SECTION_END
:
171 if (ctx
->nsections
== 3) {
172 /* End of child-sa section, update nhrp_vc */
173 int up
= sactx
->child_ok
|| sactx
->event
== 1;
175 vc
= nhrp_vc_get(&sactx
->local
.host
,
176 &sactx
->remote
.host
, up
);
178 blob2buf(&sactx
->local
.id
, vc
->local
.id
,
179 sizeof(vc
->local
.id
));
180 if (blob2buf(&sactx
->local
.cert
,
181 (char *)vc
->local
.cert
,
182 sizeof(vc
->local
.cert
)))
184 sactx
->local
.cert
.len
;
185 blob2buf(&sactx
->remote
.id
,
187 sizeof(vc
->remote
.id
));
188 if (blob2buf(&sactx
->remote
.cert
,
189 (char *)vc
->remote
.cert
,
190 sizeof(vc
->remote
.cert
)))
192 sactx
->remote
.cert
.len
;
194 nhrp_vc_ipsec_updown(
195 sactx
->child_uniqueid
,
199 nhrp_vc_ipsec_updown(sactx
->child_uniqueid
, 0);
207 switch (key
->ptr
[0]) {
209 if (blob_equal(key
, "local-host")
210 && ctx
->nsections
== 1) {
211 if (blob2buf(val
, buf
, sizeof(buf
)))
212 if (str2sockunion(buf
,
216 "VICI: bad strongSwan local-host: %s",
218 } else if (blob_equal(key
, "local-id")
219 && ctx
->nsections
== 1) {
220 sactx
->local
.id
= *val
;
221 } else if (blob_equal(key
, "local-cert-data")
222 && ctx
->nsections
== 1) {
223 sactx
->local
.cert
= *val
;
227 if (blob_equal(key
, "remote-host")
228 && ctx
->nsections
== 1) {
229 if (blob2buf(val
, buf
, sizeof(buf
)))
230 if (str2sockunion(buf
,
234 "VICI: bad strongSwan remote-host: %s",
236 } else if (blob_equal(key
, "remote-id")
237 && ctx
->nsections
== 1) {
238 sactx
->remote
.id
= *val
;
239 } else if (blob_equal(key
, "remote-cert-data")
240 && ctx
->nsections
== 1) {
241 sactx
->remote
.cert
= *val
;
245 if (blob_equal(key
, "uniqueid")
246 && blob2buf(val
, buf
, sizeof(buf
))) {
247 if (ctx
->nsections
== 3)
248 sactx
->child_uniqueid
=
249 strtoul(buf
, NULL
, 0);
250 else if (ctx
->nsections
== 1)
251 sactx
->ike_uniqueid
=
252 strtoul(buf
, NULL
, 0);
256 if (blob_equal(key
, "state") && ctx
->nsections
== 3) {
259 && (blob_equal(val
, "INSTALLED")
260 || blob_equal(val
, "REKEYED")));
268 static void parse_cmd_response(struct vici_message_ctx
*ctx
,
269 enum vici_type_t msgtype
, const struct blob
*key
,
270 const struct blob
*val
)
276 if (blob_equal(key
, "errmsg")
277 && blob2buf(val
, buf
, sizeof(buf
)))
278 zlog_err("VICI: strongSwan: %s", buf
);
285 static void vici_recv_sa(struct vici_conn
*vici
, struct zbuf
*msg
, int event
)
288 struct handle_sa_ctx ctx
= {
290 .msgctx
.nsections
= 0
293 vici_parse_message(vici
, msg
, parse_sa_message
, &ctx
.msgctx
);
295 if (ctx
.kill_ikesa
&& ctx
.ike_uniqueid
) {
296 debugf(NHRP_DEBUG_COMMON
, "VICI: Deleting IKE_SA %u",
298 snprintf(buf
, sizeof buf
, "%u", ctx
.ike_uniqueid
);
299 vici_submit_request(vici
, "terminate", VICI_KEY_VALUE
, "ike-id",
300 strlen(buf
), buf
, VICI_END
);
304 static void vici_recv_message(struct vici_conn
*vici
, struct zbuf
*msg
)
309 struct vici_message_ctx ctx
= { .nsections
= 0 };
311 msglen
= zbuf_get_be32(msg
);
312 msgtype
= zbuf_get8(msg
);
313 debugf(NHRP_DEBUG_VICI
, "VICI: Message %d, %d bytes", msgtype
, msglen
);
317 name
.len
= zbuf_get8(msg
);
318 name
.ptr
= zbuf_pulln(msg
, name
.len
);
320 debugf(NHRP_DEBUG_VICI
, "VICI: Event '%.*s'", name
.len
,
322 if (blob_equal(&name
, "list-sa")
323 || blob_equal(&name
, "child-updown")
324 || blob_equal(&name
, "child-rekey"))
325 vici_recv_sa(vici
, msg
, 0);
326 else if (blob_equal(&name
, "child-state-installed")
327 || blob_equal(&name
, "child-state-rekeyed"))
328 vici_recv_sa(vici
, msg
, 1);
329 else if (blob_equal(&name
, "child-state-destroying"))
330 vici_recv_sa(vici
, msg
, 2);
332 case VICI_CMD_RESPONSE
:
333 vici_parse_message(vici
, msg
, parse_cmd_response
, &ctx
);
335 case VICI_EVENT_UNKNOWN
:
336 case VICI_CMD_UNKNOWN
:
338 "VICI: StrongSwan does not support mandatory events (unpatched?)");
340 case VICI_EVENT_CONFIRM
:
343 zlog_notice("VICI: Unrecognized message type %d", msgtype
);
348 static int vici_read(struct thread
*t
)
350 struct vici_conn
*vici
= THREAD_ARG(t
);
351 struct zbuf
*ibuf
= &vici
->ibuf
;
355 if (zbuf_read(ibuf
, vici
->fd
, (size_t)-1) < 0) {
356 vici_connection_error(vici
);
360 /* Process all messages in buffer */
362 uint32_t *hdrlen
= zbuf_may_pull(ibuf
, uint32_t);
365 if (!zbuf_may_pulln(ibuf
, ntohl(*hdrlen
))) {
366 zbuf_reset_head(ibuf
, hdrlen
);
371 zbuf_init(&pktbuf
, hdrlen
, htonl(*hdrlen
) + 4,
373 vici_recv_message(vici
, &pktbuf
);
376 thread_add_read(master
, vici_read
, vici
, vici
->fd
, &vici
->t_read
);
380 static int vici_write(struct thread
*t
)
382 struct vici_conn
*vici
= THREAD_ARG(t
);
385 vici
->t_write
= NULL
;
386 r
= zbufq_write(&vici
->obuf
, vici
->fd
);
388 thread_add_write(master
, vici_write
, vici
, vici
->fd
,
391 vici_connection_error(vici
);
397 static void vici_submit(struct vici_conn
*vici
, struct zbuf
*obuf
)
404 zbufq_queue(&vici
->obuf
, obuf
);
405 thread_add_write(master
, vici_write
, vici
, vici
->fd
, &vici
->t_write
);
408 static void vici_submit_request(struct vici_conn
*vici
, const char *name
, ...)
416 obuf
= zbuf_alloc(256);
420 hdrlen
= zbuf_push(obuf
, uint32_t);
421 zbuf_put8(obuf
, VICI_CMD_REQUEST
);
422 vici_zbuf_puts(obuf
, name
);
425 for (type
= va_arg(va
, int); type
!= VICI_END
; type
= va_arg(va
, int)) {
426 zbuf_put8(obuf
, type
);
429 vici_zbuf_puts(obuf
, va_arg(va
, const char *));
430 len
= va_arg(va
, size_t);
431 zbuf_put_be16(obuf
, len
);
432 zbuf_put(obuf
, va_arg(va
, void *), len
);
439 *hdrlen
= htonl(zbuf_used(obuf
) - 4);
440 vici_submit(vici
, obuf
);
443 static void vici_register_event(struct vici_conn
*vici
, const char *name
)
449 namelen
= strlen(name
);
450 obuf
= zbuf_alloc(4 + 1 + 1 + namelen
);
454 hdrlen
= zbuf_push(obuf
, uint32_t);
455 zbuf_put8(obuf
, VICI_EVENT_REGISTER
);
456 zbuf_put8(obuf
, namelen
);
457 zbuf_put(obuf
, name
, namelen
);
458 *hdrlen
= htonl(zbuf_used(obuf
) - 4);
460 vici_submit(vici
, obuf
);
463 static int vici_reconnect(struct thread
*t
)
465 struct vici_conn
*vici
= THREAD_ARG(t
);
468 vici
->t_reconnect
= NULL
;
472 fd
= sock_open_unix("/var/run/charon.vici");
474 debugf(NHRP_DEBUG_VICI
,
475 "%s: failure connecting VICI socket: %s",
476 __PRETTY_FUNCTION__
, strerror(errno
));
477 thread_add_timer(master
, vici_reconnect
, vici
, 2,
482 debugf(NHRP_DEBUG_COMMON
, "VICI: Connected");
484 thread_add_read(master
, vici_read
, vici
, vici
->fd
, &vici
->t_read
);
486 /* Send event subscribtions */
487 // vici_register_event(vici, "child-updown");
488 // vici_register_event(vici, "child-rekey");
489 vici_register_event(vici
, "child-state-installed");
490 vici_register_event(vici
, "child-state-rekeyed");
491 vici_register_event(vici
, "child-state-destroying");
492 vici_register_event(vici
, "list-sa");
493 vici_submit_request(vici
, "list-sas", VICI_END
);
498 static struct vici_conn vici_connection
;
502 struct vici_conn
*vici
= &vici_connection
;
505 zbuf_init(&vici
->ibuf
, vici
->ibuf_data
, sizeof(vici
->ibuf_data
), 0);
506 zbufq_init(&vici
->obuf
);
507 thread_add_timer_msec(master
, vici_reconnect
, vici
, 10,
511 void vici_terminate(void)
515 void vici_request_vc(const char *profile
, union sockunion
*src
,
516 union sockunion
*dst
, int prio
)
518 struct vici_conn
*vici
= &vici_connection
;
519 char buf
[2][SU_ADDRSTRLEN
];
521 sockunion2str(src
, buf
[0], sizeof buf
[0]);
522 sockunion2str(dst
, buf
[1], sizeof buf
[1]);
524 vici_submit_request(vici
, "initiate", VICI_KEY_VALUE
, "child",
525 strlen(profile
), profile
, VICI_KEY_VALUE
, "timeout",
526 (size_t)2, "-1", VICI_KEY_VALUE
, "async", (size_t)1,
527 "1", VICI_KEY_VALUE
, "init-limits", (size_t)1,
528 prio
? "0" : "1", VICI_KEY_VALUE
, "my-host",
529 strlen(buf
[0]), buf
[0], VICI_KEY_VALUE
,
530 "other-host", strlen(buf
[1]), buf
[1], VICI_END
);
533 int sock_open_unix(const char *path
)
536 struct sockaddr_un addr
;
538 fd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
542 memset(&addr
, 0, sizeof(struct sockaddr_un
));
543 addr
.sun_family
= AF_UNIX
;
544 strncpy(addr
.sun_path
, path
, sizeof(addr
.sun_path
) - 1);
546 ret
= connect(fd
, (struct sockaddr
*)&addr
,
547 sizeof(addr
.sun_family
) + strlen(addr
.sun_path
));
553 ret
= fcntl(fd
, F_SETFL
, fcntl(fd
, F_GETFL
, 0) | O_NONBLOCK
);