vici.c 13 KB

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