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