kernel-netlink: Add utility to create XFRM interfaces
[strongswan.git] / src / libcharon / plugins / kernel_netlink / xfrmi.c
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
16 #include <stdio.h>
17 #include <unistd.h>
18 #include <getopt.h>
19 #include <errno.h>
20 #include <net/if.h>
21 #include <linux/netlink.h>
22 #include <linux/rtnetlink.h>
23
24 #include "kernel_netlink_shared.h"
25
26 #ifndef IFLA_XFRM_MAX
27 enum {
28 IFLA_XFRM_UNSPEC,
29 IFLA_XFRM_LINK,
30 IFLA_XFRM_IF_ID,
31 __IFLA_XFRM_MAX
32 };
33 #define IFLA_XFRM_MAX (__IFLA_XFRM_MAX - 1)
34 #endif
35
36 #define NLMSG_TAIL(nlh) ((void*)(((char*)nlh) + NLMSG_ALIGN(nlh->nlmsg_len)))
37
38 /**
39 * Create an XFRM interface with the given ID and underlying interface
40 */
41 static int add_xfrm_interface(char *name, uint32_t xfrm_id, uint32_t ifindex)
42 {
43 netlink_buf_t request;
44 struct nlmsghdr *hdr;
45 struct ifinfomsg *msg;
46 struct rtattr *linkinfo, *info_data;
47 netlink_socket_t *socket;
48 int status = 1;
49
50 socket = netlink_socket_create(NETLINK_ROUTE, NULL, FALSE);
51 if (!socket)
52 {
53 return 1;
54 }
55
56 memset(&request, 0, sizeof(request));
57
58 hdr = &request.hdr;
59 hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL;
60 hdr->nlmsg_type = RTM_NEWLINK;
61 hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
62
63 msg = NLMSG_DATA(hdr);
64 msg->ifi_family = AF_UNSPEC;
65
66 netlink_add_attribute(hdr, IFLA_IFNAME, chunk_from_str(name),
67 sizeof(request));
68
69 /* the following attributes are nested under this one */
70 linkinfo = netlink_reserve(hdr, sizeof(request), IFLA_LINKINFO, 0);
71 linkinfo = (void*)linkinfo - RTA_LENGTH(0);
72
73 netlink_add_attribute(hdr, IFLA_INFO_KIND, chunk_from_str("xfrm"),
74 sizeof(request));
75
76 /* the following attributes are nested under this one */
77 info_data = netlink_reserve(hdr, sizeof(request), IFLA_INFO_DATA, 0);
78 info_data = (void*)info_data - RTA_LENGTH(0);
79
80 netlink_add_attribute(hdr, IFLA_XFRM_IF_ID, chunk_from_thing(xfrm_id),
81 sizeof(request));
82 netlink_add_attribute(hdr, IFLA_XFRM_LINK, chunk_from_thing(ifindex),
83 sizeof(request));
84
85 info_data->rta_len = NLMSG_TAIL(hdr) - (void*)info_data;
86
87 linkinfo->rta_len = NLMSG_TAIL(hdr) - (void*)linkinfo;
88
89 switch (socket->send_ack(socket, hdr))
90 {
91 case SUCCESS:
92 status = 0;
93 break;
94 case ALREADY_DONE:
95 fprintf(stderr, "XFRM interface already exists\n");
96 break;
97 default:
98 fprintf(stderr, "failed to create XFRM interface\n");
99 break;
100 }
101
102 socket->destroy(socket);
103 return status;
104 }
105
106 static void usage(FILE *out, char *name)
107 {
108 fprintf(out, "Create XFRM interfaces\n\n");
109 fprintf(out, "%s [OPTIONS]\n\n", name);
110 fprintf(out, "Options:\n");
111 fprintf(out, " -h, --help print this help.\n");
112 fprintf(out, " -v, --debug set debug level, default: 1.\n");
113 fprintf(out, " -n, --name=NAME name of the XFRM interface.\n");
114 fprintf(out, " -i, --id=ID optional numeric XFRM ID.\n");
115 fprintf(out, " -d, --dev=DEVICE underlying physical interface.\n");
116 fprintf(out, "\n");
117 }
118
119 int main(int argc, char *argv[])
120 {
121 char *name = NULL, *dev = NULL, *end;
122 uint32_t xfrm_id = 0;
123 u_int ifindex;
124
125 while (true)
126 {
127 struct option long_opts[] = {
128 {"help", no_argument, NULL, 'h' },
129 {"debug", no_argument, NULL, 'v' },
130 {"name", required_argument, NULL, 'n' },
131 {"id", required_argument, NULL, 'i' },
132 {"dev", required_argument, NULL, 'd' },
133 {0,0,0,0 },
134 };
135 switch (getopt_long(argc, argv, "hvn:i:d:", long_opts, NULL))
136 {
137 case EOF:
138 break;
139 case 'h':
140 usage(stdout, argv[0]);
141 return 0;
142 case 'v':
143 dbg_default_set_level(atoi(optarg));
144 continue;
145 case 'n':
146 name = optarg;
147 continue;
148 case 'i':
149 errno = 0;
150 xfrm_id = strtoul(optarg, &end, 0);
151 if (errno || *end)
152 {
153 fprintf(stderr, "invalid XFRM ID: %s\n",
154 errno ? strerror(errno) : end);
155 return 1;
156 }
157 continue;
158 case 'd':
159 dev = optarg;
160 continue;
161 default:
162 usage(stderr, argv[0]);
163 return 1;
164 }
165 break;
166 }
167
168 if (!name || !dev)
169 {
170 fprintf(stderr, "please specify a name and a physical interface\n");
171 return 1;
172 }
173 ifindex = if_nametoindex(dev);
174 if (!ifindex)
175 {
176 fprintf(stderr, "physical interface %s not found\n", dev);
177 return 1;
178 }
179
180 library_init(NULL, "xfrmi");
181 atexit(library_deinit);
182
183 return add_xfrm_interface(name, xfrm_id, ifindex);
184 }