blob: 8a87cf2e7403835bec9919b482c6da71a35f4ead [file] [log] [blame]
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +00001/* $USAGI: $ */
2
3/*
4 * Copyright (C)2004 USAGI/WIDE Project
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20/*
21 * based on iproute.c
22 */
23/*
24 * Authors:
25 * Masahide NAKAMURA @USAGI
26 */
27
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <netdb.h>
32#include <linux/xfrm.h>
33#include "utils.h"
34#include "xfrm.h"
35#include "ip_common.h"
36
37//#define NLMSG_FLUSH_BUF_SIZE (4096-512)
38#define NLMSG_FLUSH_BUF_SIZE 8192
39
40/*
41 * Receiving buffer defines:
42 * nlmsg
43 * data = struct xfrm_usersa_info
44 * rtattr
45 * rtattr
46 * ... (max count of rtattr is XFRM_MAX_DEPTH)
47 *
48 * each rtattr data = struct xfrm_algo(dynamic size) or xfrm_address_t
49 */
50#define NLMSG_BUF_SIZE 4096
51#define RTA_BUF_SIZE 2048
52#define XFRM_ALGO_KEY_BUF_SIZE 512
53
54static void usage(void) __attribute__((noreturn));
55
56static void usage(void)
57{
58 fprintf(stderr, "Usage: ip xfrm state { add | update } ID [ ALGO-LIST ] [ mode MODE ]\n");
59 fprintf(stderr, " [ reqid REQID ] [ FLAG-LIST ] [ sel SELECTOR ] [ LIMIT-LIST ]\n");
60
61 fprintf(stderr, "Usage: ip xfrm state { delete | get } ID\n");
62 fprintf(stderr, "Usage: ip xfrm state { flush | list } [ ID ] [ mode MODE ] [ reqid REQID ]\n");
63 fprintf(stderr, " [ FLAG_LIST ]\n");
64
65 fprintf(stderr, "ID := [ src ADDR ] [ dst ADDR ] [ proto XFRM_PROTO ] [ spi SPI ]\n");
org[shemminger]!nakam29aa4dd2004-09-28 18:40:49 +000066 //fprintf(stderr, "XFRM_PROTO := [ esp | ah | comp ]\n");
net[shemminger]!shemminger9e566a42004-07-30 20:26:15 +000067 fprintf(stderr, "XFRM_PROTO := [ ");
org[shemminger]!nakam29aa4dd2004-09-28 18:40:49 +000068 fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_ESP));
69 fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_AH));
70 fprintf(stderr, "%s ", strxf_xfrmproto(IPPROTO_COMP));
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +000071 fprintf(stderr, "]\n");
net[shemminger]!shemminger9e566a42004-07-30 20:26:15 +000072
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +000073 //fprintf(stderr, "SPI - security parameter index(default=0)\n");
74
75 fprintf(stderr, "MODE := [ transport | tunnel ](default=transport)\n");
76 //fprintf(stderr, "REQID - number(default=0)\n");
77
78 fprintf(stderr, "FLAG-LIST := [ FLAG-LIST ] [ flag FLAG ]\n");
79 fprintf(stderr, "FLAG := [ noecn ]\n");
80
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +000081 fprintf(stderr, "ALGO-LIST := [ ALGO-LIST ] | [ ALGO ]\n");
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +000082 fprintf(stderr, "ALGO := ALGO_TYPE ALGO_NAME ALGO_KEY\n");
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +000083 fprintf(stderr, "ALGO_TYPE := [ ");
84 fprintf(stderr, "%s | ", strxf_algotype(XFRMA_ALG_CRYPT));
85 fprintf(stderr, "%s | ", strxf_algotype(XFRMA_ALG_AUTH));
86 fprintf(stderr, "%s ", strxf_algotype(XFRMA_ALG_COMP));
87 fprintf(stderr, "]\n");
88
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +000089 //fprintf(stderr, "ALGO_NAME - algorithm name\n");
90 //fprintf(stderr, "ALGO_KEY - algorithm key\n");
91
92 fprintf(stderr, "SELECTOR := src ADDR[/PLEN] dst ADDR[/PLEN] [ upspec UPSPEC ] [ dev DEV ]\n");
93
94 fprintf(stderr, "UPSPEC := proto PROTO [ sport PORT ] [ dport PORT ]\n");
95
96 //fprintf(stderr, "DEV - device name(default=none)\n");
97 fprintf(stderr, "LIMIT-LIST := [ LIMIT-LIST ] | [ limit LIMIT ]\n");
98 fprintf(stderr, "LIMIT := [ [time-soft|time-hard|time-use-soft|time-use-hard] SECONDS ] |\n");
99 fprintf(stderr, " [ [byte-soft|byte-hard] SIZE ] | [ [packet-soft|packet-hard] COUNT ]\n");
100 exit(-1);
101}
102
103static int xfrm_algo_parse(struct xfrm_algo *alg, enum xfrm_attr_type_t type,
104 char *name, char *key, int max)
105{
106 int len;
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000107 int slen = strlen(key);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000108
109#if 1
110 /* XXX: verifying both name and key is required! */
111 fprintf(stderr, "warning: ALGONAME/ALGOKEY will send to kernel promiscuously!(verifying them isn't implemented yet)\n");
112#endif
113
114 strncpy(alg->alg_name, name, sizeof(alg->alg_name));
115
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000116 if (slen > 2 && strncmp(key, "0x", 2) == 0) {
org[shemminger]!nakam54f73282004-09-28 18:36:52 +0000117 /* split two chars "0x" from the top */
118 char *p = key + 2;
119 int plen = slen - 2;
120 int i;
121 int j;
122
123 /* Converting hexadecimal numbered string into real key;
124 * Convert each two chars into one char(value). If number
125 * of the length is odd, add zero on the top for rounding.
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000126 */
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000127
org[shemminger]!nakam54f73282004-09-28 18:36:52 +0000128 /* calculate length of the converted values(real key) */
129 len = (plen + 1) / 2;
130 if (len > max)
131 invarg("\"ALGOKEY\" makes buffer overflow\n", key);
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000132
org[shemminger]!nakam54f73282004-09-28 18:36:52 +0000133 for (i = - (plen % 2), j = 0; j < len; i += 2, j++) {
134 char vbuf[3];
135 char val;
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000136
org[shemminger]!nakam54f73282004-09-28 18:36:52 +0000137 vbuf[0] = i >= 0 ? p[i] : '0';
138 vbuf[1] = p[i + 1];
139 vbuf[2] = '\0';
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000140
org[shemminger]!nakam54f73282004-09-28 18:36:52 +0000141 if (get_u8(&val, vbuf, 16))
142 invarg("\"ALGOKEY\" is invalid", key);
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000143
org[shemminger]!nakam54f73282004-09-28 18:36:52 +0000144 alg->alg_key[j] = val;
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000145 }
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000146 } else {
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000147 len = slen;
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000148 if (len > 0) {
149 if (len > max)
150 invarg("\"ALGOKEY\" makes buffer overflow\n", key);
151
152 strncpy(alg->alg_key, key, len);
153 }
154 }
155
156 alg->alg_key_len = len * 8;
157
158 return 0;
159}
160
161static int xfrm_state_flag_parse(__u8 *flags, int *argcp, char ***argvp)
162{
163 int argc = *argcp;
164 char **argv = *argvp;
net[shemminger]!shemminger9e566a42004-07-30 20:26:15 +0000165 int len = strlen(*argv);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000166
net[shemminger]!shemminger9e566a42004-07-30 20:26:15 +0000167 if (len > 2 && strncmp(*argv, "0x", 2) == 0) {
168 __u8 val = 0;
169
170 if (get_u8(&val, *argv, 16))
171 invarg("\"FLAG\" is invalid", *argv);
172 *flags = val;
173 } else {
174 if (strcmp(*argv, "noecn") == 0)
175 *flags |= XFRM_STATE_NOECN;
176 else
177 invarg("\"FLAG\" is invalid", *argv);
178 }
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000179
180 filter.state_flags_mask = XFRM_FILTER_MASK_FULL;
181
182 *argcp = argc;
183 *argvp = argv;
184
185 return 0;
186}
187
188static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
189{
190 struct rtnl_handle rth;
191 struct {
192 struct nlmsghdr n;
193 struct xfrm_usersa_info xsinfo;
194 char buf[RTA_BUF_SIZE];
195 } req;
196 char *idp = NULL;
197 char *ealgop = NULL;
198 char *aalgop = NULL;
199 char *calgop = NULL;
200
201 memset(&req, 0, sizeof(req));
202
203 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsinfo));
204 req.n.nlmsg_flags = NLM_F_REQUEST|flags;
205 req.n.nlmsg_type = cmd;
206 req.xsinfo.family = preferred_family;
207
208 req.xsinfo.lft.soft_byte_limit = XFRM_INF;
209 req.xsinfo.lft.hard_byte_limit = XFRM_INF;
210 req.xsinfo.lft.soft_packet_limit = XFRM_INF;
211 req.xsinfo.lft.hard_packet_limit = XFRM_INF;
212
213 while (argc > 0) {
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000214 if (strcmp(*argv, "mode") == 0) {
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000215 NEXT_ARG();
216 xfrm_mode_parse(&req.xsinfo.mode, &argc, &argv);
217 } else if (strcmp(*argv, "reqid") == 0) {
218 NEXT_ARG();
219 xfrm_reqid_parse(&req.xsinfo.reqid, &argc, &argv);
220 } else if (strcmp(*argv, "flag") == 0) {
221 NEXT_ARG();
222 xfrm_state_flag_parse(&req.xsinfo.flags, &argc, &argv);
223 } else if (strcmp(*argv, "sel") == 0) {
224 NEXT_ARG();
225 xfrm_selector_parse(&req.xsinfo.sel, &argc, &argv);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000226 } else if (strcmp(*argv, "limit") == 0) {
227 NEXT_ARG();
228 xfrm_lifetime_cfg_parse(&req.xsinfo.lft, &argc, &argv);
229 } else {
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000230 /* try to assume ALGO */
231 int type = xfrm_algotype_getbyname(*argv);
232 switch (type) {
233 case XFRMA_ALG_CRYPT:
234 case XFRMA_ALG_AUTH:
235 case XFRMA_ALG_COMP:
236 {
237 /* ALGO */
238 struct {
239 struct xfrm_algo alg;
240 char buf[XFRM_ALGO_KEY_BUF_SIZE];
241 } alg;
242 int len;
243 char *name;
244 char *key;
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000245
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000246 switch (type) {
247 case XFRMA_ALG_CRYPT:
248 if (ealgop)
249 duparg("ALGOTYPE", *argv);
250 ealgop = *argv;
251 break;
252 case XFRMA_ALG_AUTH:
253 if (aalgop)
254 duparg("ALGOTYPE", *argv);
255 aalgop = *argv;
256 break;
257 case XFRMA_ALG_COMP:
258 if (calgop)
259 duparg("ALGOTYPE", *argv);
260 calgop = *argv;
261 break;
262 default:
263 /* not reached */
264 invarg("\"ALGOTYPE\" is invalid\n", *argv);
265 }
266
267 if (!NEXT_ARG_OK())
268 missarg("ALGONAME");
269 NEXT_ARG();
270 name = *argv;
271
272 if (!NEXT_ARG_OK())
273 missarg("ALGOKEY");
274 NEXT_ARG();
275 key = *argv;
276
277 memset(&alg, 0, sizeof(alg));
278
279 xfrm_algo_parse((void *)&alg, type, name, key,
280 sizeof(alg.buf));
281 len = sizeof(struct xfrm_algo) + alg.alg.alg_key_len;
282
283 addattr_l(&req.n, sizeof(req.buf), type,
284 (void *)&alg, len);
285 break;
286 }
287 default:
288 /* try to assume ID */
289 if (idp)
290 invarg("unknown", *argv);
291 idp = *argv;
292
293 /* ID */
294 xfrm_id_parse(&req.xsinfo.saddr, &req.xsinfo.id,
295 &req.xsinfo.family, 0, &argc, &argv);
296 if (preferred_family == AF_UNSPEC)
297 preferred_family = req.xsinfo.family;
298 }
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000299 }
300 argc--; argv++;
301 }
302
303 if (!idp) {
304 fprintf(stderr, "Not enough information: \"ID\" is required\n");
305 exit(1);
306 }
307
308 if (ealgop || aalgop || calgop) {
309 if (req.xsinfo.id.proto != IPPROTO_ESP &&
310 req.xsinfo.id.proto != IPPROTO_AH &&
311 req.xsinfo.id.proto != IPPROTO_COMP) {
org[shemminger]!nakam29aa4dd2004-09-28 18:40:49 +0000312 fprintf(stderr, "\"ALGO\" is invalid with proto=%s\n", strxf_xfrmproto(req.xsinfo.id.proto));
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000313 exit(1);
314 }
315 } else {
316 if (req.xsinfo.id.proto == IPPROTO_ESP ||
317 req.xsinfo.id.proto == IPPROTO_AH ||
318 req.xsinfo.id.proto == IPPROTO_COMP) {
org[shemminger]!nakam29aa4dd2004-09-28 18:40:49 +0000319 fprintf(stderr, "\"ALGO\" is required with proto=%s\n", strxf_xfrmproto(req.xsinfo.id.proto));
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000320 exit (1);
321 }
322 }
323
324 if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
325 exit(1);
326
327 if (req.xsinfo.family == AF_UNSPEC)
328 req.xsinfo.family = AF_INET;
329
330 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
331 exit(2);
332
333 rtnl_close(&rth);
334
335 return 0;
336}
337
338static int xfrm_state_filter_match(struct xfrm_usersa_info *xsinfo)
339{
340 if (!filter.use)
341 return 1;
342
343 if (filter.id_src_mask)
344 if (memcmp(&xsinfo->saddr, &filter.xsinfo.saddr,
345 filter.id_src_mask) != 0)
346 return 0;
347 if (filter.id_dst_mask)
348 if (memcmp(&xsinfo->id.daddr, &filter.xsinfo.id.daddr,
349 filter.id_dst_mask) != 0)
350 return 0;
351 if ((xsinfo->id.proto^filter.xsinfo.id.proto)&filter.id_proto_mask)
352 return 0;
353 if ((xsinfo->id.spi^filter.xsinfo.id.spi)&filter.id_spi_mask)
354 return 0;
355 if ((xsinfo->mode^filter.xsinfo.mode)&filter.mode_mask)
356 return 0;
357 if ((xsinfo->reqid^filter.xsinfo.reqid)&filter.reqid_mask)
358 return 0;
359 if (filter.state_flags_mask)
360 if ((xsinfo->flags & filter.xsinfo.flags) == 0)
361 return 0;
362
363 return 1;
364}
365
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000366static int xfrm_selector_iszero(struct xfrm_selector *s)
367{
368 struct xfrm_selector s0;
369
370 memset(&s0, 0, sizeof(s0));
371
372 return (memcmp(&s0, s, sizeof(s0)) == 0);
373}
374
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000375static int xfrm_state_print(const struct sockaddr_nl *who,
376 const struct nlmsghdr *n,
377 void *arg)
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000378{
379 FILE *fp = (FILE*)arg;
380 struct xfrm_usersa_info *xsinfo = NLMSG_DATA(n);
381 int len = n->nlmsg_len;
382 struct rtattr * tb[XFRMA_MAX+1];
383 int ntb;
384
385 if (n->nlmsg_type != XFRM_MSG_NEWSA &&
386 n->nlmsg_type != XFRM_MSG_DELSA) {
387 fprintf(stderr, "Not a state: %08x %08x %08x\n",
388 n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
389 return 0;
390 }
391
392 len -= NLMSG_LENGTH(sizeof(*xsinfo));
393 if (len < 0) {
394 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
395 return -1;
396 }
397
398 if (!xfrm_state_filter_match(xsinfo))
399 return 0;
400
401 memset(tb, 0, sizeof(tb));
402 ntb = parse_rtattr_byindex(tb, XFRM_MAX_DEPTH, XFRMS_RTA(xsinfo), len);
403
404 if (n->nlmsg_type == XFRM_MSG_DELSA)
405 fprintf(fp, "Deleted ");
406
407 xfrm_id_info_print(&xsinfo->saddr, &xsinfo->id, xsinfo->mode,
408 xsinfo->reqid, xsinfo->family, fp, NULL);
409
net[shemminger]!shemminger9e566a42004-07-30 20:26:15 +0000410 fprintf(fp, "\t");
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000411 fprintf(fp, "replay-window %d ", xsinfo->replay_window);
412 if (show_stats > 0)
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000413 fprintf(fp, "seq 0x%08u ", xsinfo->seq);
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000414 if (xsinfo->flags) {
415 fprintf(fp, "flag 0x%s", strxf_flags(xsinfo->flags));
416 if (show_stats > 0) {
417 if (xsinfo->flags) {
418 fprintf(fp, "(");
419 if (xsinfo->flags & XFRM_STATE_NOECN)
420 fprintf(fp, "noecn");
421 fprintf(fp, ")");
422 }
net[shemminger]!shemminger9e566a42004-07-30 20:26:15 +0000423 }
424 }
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000425 fprintf(fp, "%s", _SL_);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000426
427 xfrm_xfrma_print(tb, ntb, xsinfo->family, fp, "\t");
428
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000429 if (!xfrm_selector_iszero(&xsinfo->sel))
430 xfrm_selector_print(&xsinfo->sel, xsinfo->family, fp, "\tsel ");
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000431
432 if (show_stats > 0) {
433 xfrm_lifetime_print(&xsinfo->lft, &xsinfo->curlft, fp, "\t");
434 xfrm_stats_print(&xsinfo->stats, fp, "\t");
435 }
436
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000437 if (oneline)
438 fprintf(fp, "\n");
439
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000440 return 0;
441}
442
443static int xfrm_state_get_or_delete(int argc, char **argv, int delete)
444{
445 struct rtnl_handle rth;
446 struct {
447 struct nlmsghdr n;
448 struct xfrm_usersa_id xsid;
449 } req;
450 struct xfrm_id id;
451 char *idp = NULL;
452
453 memset(&req, 0, sizeof(req));
454
455 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsid));
456 req.n.nlmsg_flags = NLM_F_REQUEST;
457 req.n.nlmsg_type = delete ? XFRM_MSG_DELSA : XFRM_MSG_GETSA;
458 req.xsid.family = preferred_family;
459
460 while (argc > 0) {
461 /*
462 * XXX: Source address is not used and ignore it to follow
463 * XXX: a manner of setkey e.g. in the case of deleting/getting
464 * XXX: message of IPsec SA.
465 */
466 xfrm_address_t ignore_saddr;
467
468 if (idp)
469 invarg("unknown", *argv);
470 idp = *argv;
471
472 /* ID */
473 memset(&id, 0, sizeof(id));
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000474 xfrm_id_parse(&ignore_saddr, &id, &req.xsid.family, 0,
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000475 &argc, &argv);
476
477 memcpy(&req.xsid.daddr, &id.daddr, sizeof(req.xsid.daddr));
478 req.xsid.spi = id.spi;
479 req.xsid.proto = id.proto;
480
481 argc--; argv++;
482 }
483
484 if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
485 exit(1);
486
487 if (req.xsid.family == AF_UNSPEC)
488 req.xsid.family = AF_INET;
489
490 if (delete) {
491 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
492 exit(2);
493 } else {
494 char buf[NLMSG_BUF_SIZE];
495 struct nlmsghdr *res_n = (struct nlmsghdr *)buf;
496
497 memset(buf, 0, sizeof(buf));
498
499 if (rtnl_talk(&rth, &req.n, 0, 0, res_n, NULL, NULL) < 0)
500 exit(2);
501
502 if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) {
503 fprintf(stderr, "An error :-)\n");
504 exit(1);
505 }
506 }
507
508 rtnl_close(&rth);
509
510 return 0;
511}
512
513/*
514 * With an existing state of nlmsg, make new nlmsg for deleting the state
515 * and store it to buffer.
516 */
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000517static int xfrm_state_keep(const struct sockaddr_nl *who,
518 const struct nlmsghdr *n,
519 void *arg)
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000520{
521 struct xfrm_buffer *xb = (struct xfrm_buffer *)arg;
522 struct rtnl_handle *rth = xb->rth;
523 struct xfrm_usersa_info *xsinfo = NLMSG_DATA(n);
524 int len = n->nlmsg_len;
525 struct nlmsghdr *new_n;
526 struct xfrm_usersa_id *xsid;
527
528 if (n->nlmsg_type != XFRM_MSG_NEWSA) {
529 fprintf(stderr, "Not a state: %08x %08x %08x\n",
530 n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
531 return 0;
532 }
533
534 len -= NLMSG_LENGTH(sizeof(*xsinfo));
535 if (len < 0) {
536 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
537 return -1;
538 }
539
540 if (!xfrm_state_filter_match(xsinfo))
541 return 0;
542
543 if (xb->offset > xb->size) {
544 fprintf(stderr, "Flush buffer overflow\n");
545 return -1;
546 }
547
548 new_n = (struct nlmsghdr *)(xb->buf + xb->offset);
549 new_n->nlmsg_len = NLMSG_LENGTH(sizeof(*xsid));
550 new_n->nlmsg_flags = NLM_F_REQUEST;
551 new_n->nlmsg_type = XFRM_MSG_DELSA;
552 new_n->nlmsg_seq = ++rth->seq;
553
554 xsid = NLMSG_DATA(new_n);
555 xsid->family = xsinfo->family;
556 memcpy(&xsid->daddr, &xsinfo->id.daddr, sizeof(xsid->daddr));
557 xsid->spi = xsinfo->id.spi;
558 xsid->proto = xsinfo->id.proto;
559
560 xb->offset += new_n->nlmsg_len;
561 xb->nlmsg_count ++;
562
563 return 0;
564}
565
566static int xfrm_state_list_or_flush(int argc, char **argv, int flush)
567{
568 char *idp = NULL;
569 struct rtnl_handle rth;
570
org[shemminger]!nakambd641cd2004-09-28 18:38:35 +0000571 if(argc > 0)
572 filter.use = 1;
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000573 filter.xsinfo.family = preferred_family;
574
575 while (argc > 0) {
576 if (strcmp(*argv, "mode") == 0) {
577 NEXT_ARG();
578 xfrm_mode_parse(&filter.xsinfo.mode, &argc, &argv);
579
580 filter.mode_mask = XFRM_FILTER_MASK_FULL;
581
582 } else if (strcmp(*argv, "reqid") == 0) {
583 NEXT_ARG();
584 xfrm_reqid_parse(&filter.xsinfo.reqid, &argc, &argv);
585
586 filter.reqid_mask = XFRM_FILTER_MASK_FULL;
587
588 } else if (strcmp(*argv, "flag") == 0) {
589 NEXT_ARG();
590 xfrm_state_flag_parse(&filter.xsinfo.flags, &argc, &argv);
591
592 filter.state_flags_mask = XFRM_FILTER_MASK_FULL;
593
594 } else {
595 if (idp)
596 invarg("unknown", *argv);
597 idp = *argv;
598
599 /* ID */
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000600 xfrm_id_parse(&filter.xsinfo.saddr, &filter.xsinfo.id,
601 &filter.xsinfo.family, 1, &argc, &argv);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000602 if (preferred_family == AF_UNSPEC)
603 preferred_family = filter.xsinfo.family;
604 }
605 argc--; argv++;
606 }
607
608 if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
609 exit(1);
610
611 if (flush) {
612 struct xfrm_buffer xb;
613 char buf[NLMSG_FLUSH_BUF_SIZE];
614 int i;
615
616 xb.buf = buf;
617 xb.size = sizeof(buf);
618 xb.rth = &rth;
619
620 for (i = 0; ; i++) {
621 xb.offset = 0;
622 xb.nlmsg_count = 0;
623
624 if (show_stats > 1)
625 fprintf(stderr, "Flush round = %d\n", i);
626
627 if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETSA) < 0) {
628 perror("Cannot send dump request");
629 exit(1);
630 }
631
632 if (rtnl_dump_filter(&rth, xfrm_state_keep, &xb, NULL, NULL) < 0) {
633 fprintf(stderr, "Flush terminated\n");
634 exit(1);
635 }
636 if (xb.nlmsg_count == 0) {
637 if (show_stats > 1)
638 fprintf(stderr, "Flush completed\n");
639 break;
640 }
641
642 if (rtnl_send(&rth, xb.buf, xb.offset) < 0) {
643 perror("Failed to send flush request\n");
644 exit(1);
645 }
646 if (show_stats > 1)
647 fprintf(stderr, "Flushed nlmsg count = %d\n", xb.nlmsg_count);
648
649 xb.offset = 0;
650 xb.nlmsg_count = 0;
651 }
652
653 } else {
654 if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETSA) < 0) {
655 perror("Cannot send dump request");
656 exit(1);
657 }
658
659 if (rtnl_dump_filter(&rth, xfrm_state_print, stdout, NULL, NULL) < 0) {
660 fprintf(stderr, "Dump terminated\n");
661 exit(1);
662 }
663 }
664
665 rtnl_close(&rth);
666
667 exit(0);
668}
669
org[shemminger]!nakambd641cd2004-09-28 18:38:35 +0000670static int xfrm_state_flush_all(void)
671{
672 struct rtnl_handle rth;
673 struct {
674 struct nlmsghdr n;
675 struct xfrm_usersa_flush xsf;
676 } req;
677
678 memset(&req, 0, sizeof(req));
679
680 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsf));
681 req.n.nlmsg_flags = NLM_F_REQUEST;
682 req.n.nlmsg_type = XFRM_MSG_FLUSHSA;
683 req.xsf.proto = IPSEC_PROTO_ANY;
684
685 if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
686 exit(1);
687
688 if (show_stats > 1)
689 fprintf(stderr, "Flush all\n");
690
691 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
692 exit(2);
693
694 rtnl_close(&rth);
695
696 return 0;
697}
698
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000699int do_xfrm_state(int argc, char **argv)
700{
701 if (argc < 1)
702 return xfrm_state_list_or_flush(0, NULL, 0);
703
704 if (matches(*argv, "add") == 0)
705 return xfrm_state_modify(XFRM_MSG_NEWSA, 0,
706 argc-1, argv+1);
707 if (matches(*argv, "update") == 0)
708 return xfrm_state_modify(XFRM_MSG_UPDSA, 0,
709 argc-1, argv+1);
710 if (matches(*argv, "delete") == 0 || matches(*argv, "del") == 0)
711 return xfrm_state_get_or_delete(argc-1, argv+1, 1);
712 if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
713 || matches(*argv, "lst") == 0)
714 return xfrm_state_list_or_flush(argc-1, argv+1, 0);
715 if (matches(*argv, "get") == 0)
716 return xfrm_state_get_or_delete(argc-1, argv+1, 0);
org[shemminger]!nakambd641cd2004-09-28 18:38:35 +0000717 if (matches(*argv, "flush") == 0) {
718 if (argc-1 < 1)
719 return xfrm_state_flush_all();
720 else
721 return xfrm_state_list_or_flush(argc-1, argv+1, 1);
722 }
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000723 if (matches(*argv, "help") == 0)
724 usage();
725 fprintf(stderr, "Command \"%s\" is unknown, try \"ip xfrm state help\".\n", *argv);
726 exit(-1);
727}