xfrmi.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /*
  2. * Copyright (C) 2019 Tobias Brunner
  3. * HSR Hochschule fuer Technik Rapperswil
  4. *
  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>.
  9. *
  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
  13. * for more details.
  14. */
  15. #include <stdio.h>
  16. #include <unistd.h>
  17. #include <getopt.h>
  18. #include <errno.h>
  19. #include <net/if.h>
  20. #include <linux/netlink.h>
  21. #include <linux/rtnetlink.h>
  22. #include "kernel_netlink_shared.h"
  23. #ifndef IFLA_XFRM_MAX
  24. enum {
  25. IFLA_XFRM_UNSPEC,
  26. IFLA_XFRM_LINK,
  27. IFLA_XFRM_IF_ID,
  28. __IFLA_XFRM_MAX
  29. };
  30. #define IFLA_XFRM_MAX (__IFLA_XFRM_MAX - 1)
  31. #endif
  32. /**
  33. * Create an XFRM interface with the given ID and underlying interface
  34. */
  35. static int add_xfrm_interface(char *name, uint32_t xfrm_id, uint32_t ifindex)
  36. {
  37. netlink_buf_t request;
  38. struct nlmsghdr *hdr;
  39. struct ifinfomsg *msg;
  40. struct rtattr *linkinfo, *info_data;
  41. netlink_socket_t *socket;
  42. int status = 1;
  43. socket = netlink_socket_create(NETLINK_ROUTE, NULL, FALSE);
  44. if (!socket)
  45. {
  46. return 1;
  47. }
  48. memset(&request, 0, sizeof(request));
  49. hdr = &request.hdr;
  50. hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL;
  51. hdr->nlmsg_type = RTM_NEWLINK;
  52. hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
  53. msg = NLMSG_DATA(hdr);
  54. msg->ifi_family = AF_UNSPEC;
  55. netlink_add_attribute(hdr, IFLA_IFNAME, chunk_from_str(name),
  56. sizeof(request));
  57. linkinfo = netlink_nested_start(hdr, sizeof(request), IFLA_LINKINFO);
  58. netlink_add_attribute(hdr, IFLA_INFO_KIND, chunk_from_str("xfrm"),
  59. sizeof(request));
  60. info_data = netlink_nested_start(hdr, sizeof(request), IFLA_INFO_DATA);
  61. netlink_add_attribute(hdr, IFLA_XFRM_IF_ID, chunk_from_thing(xfrm_id),
  62. sizeof(request));
  63. netlink_add_attribute(hdr, IFLA_XFRM_LINK, chunk_from_thing(ifindex),
  64. sizeof(request));
  65. netlink_nested_end(hdr, info_data);
  66. netlink_nested_end(hdr, linkinfo);
  67. switch (socket->send_ack(socket, hdr))
  68. {
  69. case SUCCESS:
  70. status = 0;
  71. break;
  72. case ALREADY_DONE:
  73. fprintf(stderr, "XFRM interface already exists\n");
  74. break;
  75. default:
  76. fprintf(stderr, "failed to create XFRM interface\n");
  77. break;
  78. }
  79. socket->destroy(socket);
  80. return status;
  81. }
  82. /**
  83. * Parse attributes nested in IFLA_INFO_DATA
  84. */
  85. static void parse_info_data(struct rtattr *rta, size_t rtasize, char *phys,
  86. uint32_t *if_id)
  87. {
  88. uint32_t ifindex;
  89. while (RTA_OK(rta, rtasize))
  90. {
  91. switch (rta->rta_type)
  92. {
  93. case IFLA_XFRM_IF_ID:
  94. if (RTA_PAYLOAD(rta) == sizeof(*if_id))
  95. {
  96. *if_id = *(uint32_t*)RTA_DATA(rta);
  97. }
  98. break;
  99. case IFLA_XFRM_LINK:
  100. if (RTA_PAYLOAD(rta) == sizeof(ifindex))
  101. {
  102. ifindex = *(uint32_t*)RTA_DATA(rta);
  103. if_indextoname(ifindex, phys);
  104. }
  105. break;
  106. default:
  107. break;
  108. }
  109. rta = RTA_NEXT(rta, rtasize);
  110. }
  111. }
  112. /**
  113. * Parse attributes nested in IFLA_LINKINFO
  114. */
  115. static void parse_linkinfo(struct rtattr *rta, size_t rtasize, char *phys,
  116. uint32_t *if_id)
  117. {
  118. while (RTA_OK(rta, rtasize))
  119. {
  120. switch (rta->rta_type)
  121. {
  122. case IFLA_INFO_DATA:
  123. parse_info_data(RTA_DATA(rta), RTA_PAYLOAD(rta), phys, if_id);
  124. break;
  125. default:
  126. break;
  127. }
  128. rta = RTA_NEXT(rta, rtasize);
  129. }
  130. }
  131. /**
  132. * List all installed XFRM interfaces
  133. */
  134. static int list_xfrm_interfaces()
  135. {
  136. netlink_buf_t request;
  137. struct nlmsghdr *hdr, *out, *current;
  138. struct ifinfomsg *msg;
  139. struct rtattr *linkinfo;
  140. netlink_socket_t *socket;
  141. size_t len;
  142. int status = 0;
  143. socket = netlink_socket_create(NETLINK_ROUTE, NULL, FALSE);
  144. if (!socket)
  145. {
  146. return 1;
  147. }
  148. memset(&request, 0, sizeof(request));
  149. hdr = &request.hdr;
  150. hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
  151. hdr->nlmsg_type = RTM_GETLINK;
  152. hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
  153. msg = NLMSG_DATA(hdr);
  154. msg->ifi_family = AF_UNSPEC;
  155. linkinfo = netlink_nested_start(hdr, sizeof(request), IFLA_LINKINFO);
  156. netlink_add_attribute(hdr, IFLA_INFO_KIND, chunk_from_str("xfrm"),
  157. sizeof(request));
  158. netlink_nested_end(hdr, linkinfo);
  159. if (socket->send(socket, hdr, &out, &len) != SUCCESS)
  160. {
  161. return FAILED;
  162. }
  163. current = out;
  164. while (NLMSG_OK(current, len))
  165. {
  166. switch (current->nlmsg_type)
  167. {
  168. case NLMSG_DONE:
  169. break;
  170. case RTM_NEWLINK:
  171. msg = NLMSG_DATA(current);
  172. struct rtattr *rta = IFLA_RTA(msg);
  173. size_t rtasize = IFLA_PAYLOAD(current);
  174. char *name = NULL, phys[IF_NAMESIZE] = {};
  175. uint32_t if_id = 0;
  176. while (RTA_OK(rta, rtasize))
  177. {
  178. switch (rta->rta_type)
  179. {
  180. case IFLA_IFNAME:
  181. name = RTA_DATA(rta);
  182. break;
  183. case IFLA_LINKINFO:
  184. parse_linkinfo(RTA_DATA(rta), RTA_PAYLOAD(rta),
  185. phys, &if_id);
  186. break;
  187. default:
  188. break;
  189. }
  190. rta = RTA_NEXT(rta, rtasize);
  191. }
  192. if (name)
  193. {
  194. printf("%2u: %-16s dev %-8s if_id 0x%.8x [%u]\n",
  195. msg->ifi_index, name, phys, if_id, if_id);
  196. }
  197. /* fall through */
  198. default:
  199. current = NLMSG_NEXT(current, len);
  200. continue;
  201. }
  202. break;
  203. }
  204. free(out);
  205. socket->destroy(socket);
  206. return status;
  207. }
  208. static void usage(FILE *out, char *name)
  209. {
  210. fprintf(out, "Create XFRM interfaces\n\n");
  211. fprintf(out, "%s [OPTIONS]\n\n", name);
  212. fprintf(out, "Options:\n");
  213. fprintf(out, " -h, --help print this help.\n");
  214. fprintf(out, " -v, --debug set debug level, default: 1.\n");
  215. fprintf(out, " -l, --list list XFRM interfaces.\n");
  216. fprintf(out, " -n, --name=NAME name of the XFRM interface.\n");
  217. fprintf(out, " -i, --id=ID optional numeric XFRM ID.\n");
  218. fprintf(out, " -d, --dev=DEVICE underlying physical interface.\n");
  219. fprintf(out, "\n");
  220. }
  221. int main(int argc, char *argv[])
  222. {
  223. char *name = NULL, *dev = NULL, *end;
  224. uint32_t xfrm_id = 0;
  225. u_int ifindex;
  226. library_init(NULL, "xfrmi");
  227. atexit(library_deinit);
  228. while (true)
  229. {
  230. struct option long_opts[] = {
  231. {"help", no_argument, NULL, 'h' },
  232. {"debug", no_argument, NULL, 'v' },
  233. {"list", no_argument, NULL, 'l' },
  234. {"name", required_argument, NULL, 'n' },
  235. {"id", required_argument, NULL, 'i' },
  236. {"dev", required_argument, NULL, 'd' },
  237. {0,0,0,0 },
  238. };
  239. switch (getopt_long(argc, argv, "hvln:i:d:", long_opts, NULL))
  240. {
  241. case EOF:
  242. break;
  243. case 'h':
  244. usage(stdout, argv[0]);
  245. return 0;
  246. case 'l':
  247. list_xfrm_interfaces();
  248. return 0;
  249. case 'v':
  250. dbg_default_set_level(atoi(optarg));
  251. continue;
  252. case 'n':
  253. name = optarg;
  254. continue;
  255. case 'i':
  256. errno = 0;
  257. xfrm_id = strtoul(optarg, &end, 0);
  258. if (errno || *end)
  259. {
  260. fprintf(stderr, "invalid XFRM ID: %s\n",
  261. errno ? strerror(errno) : end);
  262. return 1;
  263. }
  264. continue;
  265. case 'd':
  266. dev = optarg;
  267. continue;
  268. default:
  269. usage(stderr, argv[0]);
  270. return 1;
  271. }
  272. break;
  273. }
  274. if (!name || !dev)
  275. {
  276. fprintf(stderr, "please specify a name and a physical interface\n");
  277. return 1;
  278. }
  279. ifindex = if_nametoindex(dev);
  280. if (!ifindex)
  281. {
  282. fprintf(stderr, "physical interface %s not found\n", dev);
  283. return 1;
  284. }
  285. return add_xfrm_interface(name, xfrm_id, ifindex);
  286. }