]> git.proxmox.com Git - mirror_iproute2.git/blame - ip/xfrm_state.c
Fix for older /usr/include headers.
[mirror_iproute2.git] / ip / xfrm_state.c
CommitLineData
c7699875 1/* $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");
29aa4dd7 66 //fprintf(stderr, "XFRM_PROTO := [ esp | ah | comp ]\n");
9e566a46 67 fprintf(stderr, "XFRM_PROTO := [ ");
29aa4dd7 68 fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_ESP));
69 fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_AH));
70 fprintf(stderr, "%s ", strxf_xfrmproto(IPPROTO_COMP));
7809c616 71 fprintf(stderr, "]\n");
9e566a46 72
c7699875 73 //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
7809c616 81 fprintf(stderr, "ALGO-LIST := [ ALGO-LIST ] | [ ALGO ]\n");
c7699875 82 fprintf(stderr, "ALGO := ALGO_TYPE ALGO_NAME ALGO_KEY\n");
7809c616 83 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
c7699875 89 //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
c70b36d2 94 fprintf(stderr, "UPSPEC := proto PROTO [ [ sport PORT ] [ dport PORT ] |\n");
95 fprintf(stderr, " [ type NUMBER ] [ code NUMBER ] ]\n");
96
c7699875 97
98 //fprintf(stderr, "DEV - device name(default=none)\n");
99 fprintf(stderr, "LIMIT-LIST := [ LIMIT-LIST ] | [ limit LIMIT ]\n");
100 fprintf(stderr, "LIMIT := [ [time-soft|time-hard|time-use-soft|time-use-hard] SECONDS ] |\n");
101 fprintf(stderr, " [ [byte-soft|byte-hard] SIZE ] | [ [packet-soft|packet-hard] COUNT ]\n");
102 exit(-1);
103}
104
105static int xfrm_algo_parse(struct xfrm_algo *alg, enum xfrm_attr_type_t type,
106 char *name, char *key, int max)
107{
108 int len;
7809c616 109 int slen = strlen(key);
c7699875 110
111#if 1
112 /* XXX: verifying both name and key is required! */
113 fprintf(stderr, "warning: ALGONAME/ALGOKEY will send to kernel promiscuously!(verifying them isn't implemented yet)\n");
114#endif
115
116 strncpy(alg->alg_name, name, sizeof(alg->alg_name));
117
7809c616 118 if (slen > 2 && strncmp(key, "0x", 2) == 0) {
54f7328a 119 /* split two chars "0x" from the top */
120 char *p = key + 2;
121 int plen = slen - 2;
122 int i;
123 int j;
124
125 /* Converting hexadecimal numbered string into real key;
126 * Convert each two chars into one char(value). If number
127 * of the length is odd, add zero on the top for rounding.
c7699875 128 */
7809c616 129
54f7328a 130 /* calculate length of the converted values(real key) */
131 len = (plen + 1) / 2;
132 if (len > max)
133 invarg("\"ALGOKEY\" makes buffer overflow\n", key);
c7699875 134
54f7328a 135 for (i = - (plen % 2), j = 0; j < len; i += 2, j++) {
136 char vbuf[3];
137 char val;
c7699875 138
54f7328a 139 vbuf[0] = i >= 0 ? p[i] : '0';
140 vbuf[1] = p[i + 1];
141 vbuf[2] = '\0';
c7699875 142
54f7328a 143 if (get_u8(&val, vbuf, 16))
144 invarg("\"ALGOKEY\" is invalid", key);
7809c616 145
54f7328a 146 alg->alg_key[j] = val;
c7699875 147 }
c7699875 148 } else {
7809c616 149 len = slen;
c7699875 150 if (len > 0) {
151 if (len > max)
152 invarg("\"ALGOKEY\" makes buffer overflow\n", key);
153
154 strncpy(alg->alg_key, key, len);
155 }
156 }
157
158 alg->alg_key_len = len * 8;
159
160 return 0;
161}
162
163static int xfrm_state_flag_parse(__u8 *flags, int *argcp, char ***argvp)
164{
165 int argc = *argcp;
166 char **argv = *argvp;
9e566a46 167 int len = strlen(*argv);
168
169 if (len > 2 && strncmp(*argv, "0x", 2) == 0) {
170 __u8 val = 0;
c7699875 171
9e566a46 172 if (get_u8(&val, *argv, 16))
173 invarg("\"FLAG\" is invalid", *argv);
174 *flags = val;
175 } else {
176 if (strcmp(*argv, "noecn") == 0)
177 *flags |= XFRM_STATE_NOECN;
178 else
179 invarg("\"FLAG\" is invalid", *argv);
180 }
c7699875 181
182 filter.state_flags_mask = XFRM_FILTER_MASK_FULL;
183
184 *argcp = argc;
185 *argvp = argv;
186
187 return 0;
188}
189
190static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
191{
192 struct rtnl_handle rth;
193 struct {
194 struct nlmsghdr n;
195 struct xfrm_usersa_info xsinfo;
196 char buf[RTA_BUF_SIZE];
197 } req;
198 char *idp = NULL;
199 char *ealgop = NULL;
200 char *aalgop = NULL;
201 char *calgop = NULL;
202
203 memset(&req, 0, sizeof(req));
204
205 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsinfo));
206 req.n.nlmsg_flags = NLM_F_REQUEST|flags;
207 req.n.nlmsg_type = cmd;
208 req.xsinfo.family = preferred_family;
209
210 req.xsinfo.lft.soft_byte_limit = XFRM_INF;
211 req.xsinfo.lft.hard_byte_limit = XFRM_INF;
212 req.xsinfo.lft.soft_packet_limit = XFRM_INF;
213 req.xsinfo.lft.hard_packet_limit = XFRM_INF;
214
215 while (argc > 0) {
7809c616 216 if (strcmp(*argv, "mode") == 0) {
c7699875 217 NEXT_ARG();
218 xfrm_mode_parse(&req.xsinfo.mode, &argc, &argv);
219 } else if (strcmp(*argv, "reqid") == 0) {
220 NEXT_ARG();
221 xfrm_reqid_parse(&req.xsinfo.reqid, &argc, &argv);
222 } else if (strcmp(*argv, "flag") == 0) {
223 NEXT_ARG();
224 xfrm_state_flag_parse(&req.xsinfo.flags, &argc, &argv);
225 } else if (strcmp(*argv, "sel") == 0) {
226 NEXT_ARG();
227 xfrm_selector_parse(&req.xsinfo.sel, &argc, &argv);
c7699875 228 } else if (strcmp(*argv, "limit") == 0) {
229 NEXT_ARG();
230 xfrm_lifetime_cfg_parse(&req.xsinfo.lft, &argc, &argv);
231 } else {
7809c616 232 /* try to assume ALGO */
233 int type = xfrm_algotype_getbyname(*argv);
234 switch (type) {
235 case XFRMA_ALG_CRYPT:
236 case XFRMA_ALG_AUTH:
237 case XFRMA_ALG_COMP:
238 {
239 /* ALGO */
240 struct {
241 struct xfrm_algo alg;
242 char buf[XFRM_ALGO_KEY_BUF_SIZE];
243 } alg;
244 int len;
245 char *name;
246 char *key;
247
248 switch (type) {
249 case XFRMA_ALG_CRYPT:
250 if (ealgop)
251 duparg("ALGOTYPE", *argv);
252 ealgop = *argv;
253 break;
254 case XFRMA_ALG_AUTH:
255 if (aalgop)
256 duparg("ALGOTYPE", *argv);
257 aalgop = *argv;
258 break;
259 case XFRMA_ALG_COMP:
260 if (calgop)
261 duparg("ALGOTYPE", *argv);
262 calgop = *argv;
263 break;
264 default:
265 /* not reached */
266 invarg("\"ALGOTYPE\" is invalid\n", *argv);
267 }
268
269 if (!NEXT_ARG_OK())
270 missarg("ALGONAME");
271 NEXT_ARG();
272 name = *argv;
273
274 if (!NEXT_ARG_OK())
275 missarg("ALGOKEY");
276 NEXT_ARG();
277 key = *argv;
278
279 memset(&alg, 0, sizeof(alg));
280
281 xfrm_algo_parse((void *)&alg, type, name, key,
282 sizeof(alg.buf));
283 len = sizeof(struct xfrm_algo) + alg.alg.alg_key_len;
284
285 addattr_l(&req.n, sizeof(req.buf), type,
286 (void *)&alg, len);
287 break;
288 }
289 default:
290 /* try to assume ID */
291 if (idp)
292 invarg("unknown", *argv);
293 idp = *argv;
294
295 /* ID */
296 xfrm_id_parse(&req.xsinfo.saddr, &req.xsinfo.id,
297 &req.xsinfo.family, 0, &argc, &argv);
298 if (preferred_family == AF_UNSPEC)
299 preferred_family = req.xsinfo.family;
300 }
c7699875 301 }
302 argc--; argv++;
303 }
304
305 if (!idp) {
306 fprintf(stderr, "Not enough information: \"ID\" is required\n");
307 exit(1);
308 }
309
310 if (ealgop || aalgop || calgop) {
311 if (req.xsinfo.id.proto != IPPROTO_ESP &&
312 req.xsinfo.id.proto != IPPROTO_AH &&
313 req.xsinfo.id.proto != IPPROTO_COMP) {
29aa4dd7 314 fprintf(stderr, "\"ALGO\" is invalid with proto=%s\n", strxf_xfrmproto(req.xsinfo.id.proto));
c7699875 315 exit(1);
316 }
317 } else {
318 if (req.xsinfo.id.proto == IPPROTO_ESP ||
319 req.xsinfo.id.proto == IPPROTO_AH ||
320 req.xsinfo.id.proto == IPPROTO_COMP) {
29aa4dd7 321 fprintf(stderr, "\"ALGO\" is required with proto=%s\n", strxf_xfrmproto(req.xsinfo.id.proto));
c7699875 322 exit (1);
323 }
324 }
325
326 if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
327 exit(1);
328
329 if (req.xsinfo.family == AF_UNSPEC)
330 req.xsinfo.family = AF_INET;
331
332 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
333 exit(2);
334
335 rtnl_close(&rth);
336
337 return 0;
338}
339
340static int xfrm_state_filter_match(struct xfrm_usersa_info *xsinfo)
341{
342 if (!filter.use)
343 return 1;
344
345 if (filter.id_src_mask)
346 if (memcmp(&xsinfo->saddr, &filter.xsinfo.saddr,
347 filter.id_src_mask) != 0)
348 return 0;
349 if (filter.id_dst_mask)
350 if (memcmp(&xsinfo->id.daddr, &filter.xsinfo.id.daddr,
351 filter.id_dst_mask) != 0)
352 return 0;
353 if ((xsinfo->id.proto^filter.xsinfo.id.proto)&filter.id_proto_mask)
354 return 0;
355 if ((xsinfo->id.spi^filter.xsinfo.id.spi)&filter.id_spi_mask)
356 return 0;
357 if ((xsinfo->mode^filter.xsinfo.mode)&filter.mode_mask)
358 return 0;
359 if ((xsinfo->reqid^filter.xsinfo.reqid)&filter.reqid_mask)
360 return 0;
361 if (filter.state_flags_mask)
362 if ((xsinfo->flags & filter.xsinfo.flags) == 0)
363 return 0;
364
365 return 1;
366}
367
7809c616 368static int xfrm_selector_iszero(struct xfrm_selector *s)
369{
370 struct xfrm_selector s0;
371
372 memset(&s0, 0, sizeof(s0));
373
374 return (memcmp(&s0, s, sizeof(s0)) == 0);
375}
376
6dc9f016
SH
377static int xfrm_state_print(const struct sockaddr_nl *who,
378 const struct nlmsghdr *n,
379 void *arg)
c7699875 380{
381 FILE *fp = (FILE*)arg;
382 struct xfrm_usersa_info *xsinfo = NLMSG_DATA(n);
383 int len = n->nlmsg_len;
384 struct rtattr * tb[XFRMA_MAX+1];
385 int ntb;
386
387 if (n->nlmsg_type != XFRM_MSG_NEWSA &&
388 n->nlmsg_type != XFRM_MSG_DELSA) {
389 fprintf(stderr, "Not a state: %08x %08x %08x\n",
390 n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
391 return 0;
392 }
393
394 len -= NLMSG_LENGTH(sizeof(*xsinfo));
395 if (len < 0) {
396 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
397 return -1;
398 }
399
400 if (!xfrm_state_filter_match(xsinfo))
401 return 0;
402
403 memset(tb, 0, sizeof(tb));
404 ntb = parse_rtattr_byindex(tb, XFRM_MAX_DEPTH, XFRMS_RTA(xsinfo), len);
405
406 if (n->nlmsg_type == XFRM_MSG_DELSA)
407 fprintf(fp, "Deleted ");
408
409 xfrm_id_info_print(&xsinfo->saddr, &xsinfo->id, xsinfo->mode,
410 xsinfo->reqid, xsinfo->family, fp, NULL);
411
9e566a46 412 fprintf(fp, "\t");
7809c616 413 fprintf(fp, "replay-window %d ", xsinfo->replay_window);
414 if (show_stats > 0)
c7699875 415 fprintf(fp, "seq 0x%08u ", xsinfo->seq);
7809c616 416 if (xsinfo->flags) {
417 fprintf(fp, "flag 0x%s", strxf_flags(xsinfo->flags));
418 if (show_stats > 0) {
419 if (xsinfo->flags) {
420 fprintf(fp, "(");
421 if (xsinfo->flags & XFRM_STATE_NOECN)
422 fprintf(fp, "noecn");
423 fprintf(fp, ")");
424 }
9e566a46 425 }
426 }
7809c616 427 fprintf(fp, "%s", _SL_);
c7699875 428
429 xfrm_xfrma_print(tb, ntb, xsinfo->family, fp, "\t");
430
7809c616 431 if (!xfrm_selector_iszero(&xsinfo->sel))
432 xfrm_selector_print(&xsinfo->sel, xsinfo->family, fp, "\tsel ");
c7699875 433
434 if (show_stats > 0) {
435 xfrm_lifetime_print(&xsinfo->lft, &xsinfo->curlft, fp, "\t");
436 xfrm_stats_print(&xsinfo->stats, fp, "\t");
437 }
438
7809c616 439 if (oneline)
440 fprintf(fp, "\n");
441
c7699875 442 return 0;
443}
444
445static int xfrm_state_get_or_delete(int argc, char **argv, int delete)
446{
447 struct rtnl_handle rth;
448 struct {
449 struct nlmsghdr n;
450 struct xfrm_usersa_id xsid;
451 } req;
452 struct xfrm_id id;
453 char *idp = NULL;
454
455 memset(&req, 0, sizeof(req));
456
457 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsid));
458 req.n.nlmsg_flags = NLM_F_REQUEST;
459 req.n.nlmsg_type = delete ? XFRM_MSG_DELSA : XFRM_MSG_GETSA;
460 req.xsid.family = preferred_family;
461
462 while (argc > 0) {
463 /*
464 * XXX: Source address is not used and ignore it to follow
465 * XXX: a manner of setkey e.g. in the case of deleting/getting
466 * XXX: message of IPsec SA.
467 */
468 xfrm_address_t ignore_saddr;
469
470 if (idp)
471 invarg("unknown", *argv);
472 idp = *argv;
473
474 /* ID */
475 memset(&id, 0, sizeof(id));
7809c616 476 xfrm_id_parse(&ignore_saddr, &id, &req.xsid.family, 0,
c7699875 477 &argc, &argv);
478
479 memcpy(&req.xsid.daddr, &id.daddr, sizeof(req.xsid.daddr));
480 req.xsid.spi = id.spi;
481 req.xsid.proto = id.proto;
482
483 argc--; argv++;
484 }
485
486 if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
487 exit(1);
488
489 if (req.xsid.family == AF_UNSPEC)
490 req.xsid.family = AF_INET;
491
492 if (delete) {
493 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
494 exit(2);
495 } else {
496 char buf[NLMSG_BUF_SIZE];
497 struct nlmsghdr *res_n = (struct nlmsghdr *)buf;
498
499 memset(buf, 0, sizeof(buf));
500
501 if (rtnl_talk(&rth, &req.n, 0, 0, res_n, NULL, NULL) < 0)
502 exit(2);
503
504 if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) {
505 fprintf(stderr, "An error :-)\n");
506 exit(1);
507 }
508 }
509
510 rtnl_close(&rth);
511
512 return 0;
513}
514
515/*
516 * With an existing state of nlmsg, make new nlmsg for deleting the state
517 * and store it to buffer.
518 */
6dc9f016
SH
519static int xfrm_state_keep(const struct sockaddr_nl *who,
520 const struct nlmsghdr *n,
521 void *arg)
c7699875 522{
523 struct xfrm_buffer *xb = (struct xfrm_buffer *)arg;
524 struct rtnl_handle *rth = xb->rth;
525 struct xfrm_usersa_info *xsinfo = NLMSG_DATA(n);
526 int len = n->nlmsg_len;
527 struct nlmsghdr *new_n;
528 struct xfrm_usersa_id *xsid;
529
530 if (n->nlmsg_type != XFRM_MSG_NEWSA) {
531 fprintf(stderr, "Not a state: %08x %08x %08x\n",
532 n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
533 return 0;
534 }
535
536 len -= NLMSG_LENGTH(sizeof(*xsinfo));
537 if (len < 0) {
538 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
539 return -1;
540 }
541
542 if (!xfrm_state_filter_match(xsinfo))
543 return 0;
544
545 if (xb->offset > xb->size) {
546 fprintf(stderr, "Flush buffer overflow\n");
547 return -1;
548 }
549
550 new_n = (struct nlmsghdr *)(xb->buf + xb->offset);
551 new_n->nlmsg_len = NLMSG_LENGTH(sizeof(*xsid));
552 new_n->nlmsg_flags = NLM_F_REQUEST;
553 new_n->nlmsg_type = XFRM_MSG_DELSA;
554 new_n->nlmsg_seq = ++rth->seq;
555
556 xsid = NLMSG_DATA(new_n);
557 xsid->family = xsinfo->family;
558 memcpy(&xsid->daddr, &xsinfo->id.daddr, sizeof(xsid->daddr));
559 xsid->spi = xsinfo->id.spi;
560 xsid->proto = xsinfo->id.proto;
561
562 xb->offset += new_n->nlmsg_len;
563 xb->nlmsg_count ++;
564
565 return 0;
566}
567
568static int xfrm_state_list_or_flush(int argc, char **argv, int flush)
569{
570 char *idp = NULL;
571 struct rtnl_handle rth;
572
bd641cd6 573 if(argc > 0)
574 filter.use = 1;
c7699875 575 filter.xsinfo.family = preferred_family;
576
577 while (argc > 0) {
578 if (strcmp(*argv, "mode") == 0) {
579 NEXT_ARG();
580 xfrm_mode_parse(&filter.xsinfo.mode, &argc, &argv);
581
582 filter.mode_mask = XFRM_FILTER_MASK_FULL;
583
584 } else if (strcmp(*argv, "reqid") == 0) {
585 NEXT_ARG();
586 xfrm_reqid_parse(&filter.xsinfo.reqid, &argc, &argv);
587
588 filter.reqid_mask = XFRM_FILTER_MASK_FULL;
589
590 } else if (strcmp(*argv, "flag") == 0) {
591 NEXT_ARG();
592 xfrm_state_flag_parse(&filter.xsinfo.flags, &argc, &argv);
593
594 filter.state_flags_mask = XFRM_FILTER_MASK_FULL;
595
596 } else {
597 if (idp)
598 invarg("unknown", *argv);
599 idp = *argv;
600
601 /* ID */
7809c616 602 xfrm_id_parse(&filter.xsinfo.saddr, &filter.xsinfo.id,
603 &filter.xsinfo.family, 1, &argc, &argv);
c7699875 604 if (preferred_family == AF_UNSPEC)
605 preferred_family = filter.xsinfo.family;
606 }
607 argc--; argv++;
608 }
609
610 if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
611 exit(1);
612
613 if (flush) {
614 struct xfrm_buffer xb;
615 char buf[NLMSG_FLUSH_BUF_SIZE];
616 int i;
617
618 xb.buf = buf;
619 xb.size = sizeof(buf);
620 xb.rth = &rth;
621
622 for (i = 0; ; i++) {
623 xb.offset = 0;
624 xb.nlmsg_count = 0;
625
626 if (show_stats > 1)
627 fprintf(stderr, "Flush round = %d\n", i);
628
629 if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETSA) < 0) {
630 perror("Cannot send dump request");
631 exit(1);
632 }
633
634 if (rtnl_dump_filter(&rth, xfrm_state_keep, &xb, NULL, NULL) < 0) {
635 fprintf(stderr, "Flush terminated\n");
636 exit(1);
637 }
638 if (xb.nlmsg_count == 0) {
639 if (show_stats > 1)
640 fprintf(stderr, "Flush completed\n");
641 break;
642 }
643
644 if (rtnl_send(&rth, xb.buf, xb.offset) < 0) {
645 perror("Failed to send flush request\n");
646 exit(1);
647 }
648 if (show_stats > 1)
649 fprintf(stderr, "Flushed nlmsg count = %d\n", xb.nlmsg_count);
650
651 xb.offset = 0;
652 xb.nlmsg_count = 0;
653 }
654
655 } else {
656 if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETSA) < 0) {
657 perror("Cannot send dump request");
658 exit(1);
659 }
660
661 if (rtnl_dump_filter(&rth, xfrm_state_print, stdout, NULL, NULL) < 0) {
662 fprintf(stderr, "Dump terminated\n");
663 exit(1);
664 }
665 }
666
667 rtnl_close(&rth);
668
669 exit(0);
670}
671
bd641cd6 672static int xfrm_state_flush_all(void)
673{
674 struct rtnl_handle rth;
675 struct {
676 struct nlmsghdr n;
677 struct xfrm_usersa_flush xsf;
678 } req;
679
680 memset(&req, 0, sizeof(req));
681
682 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsf));
683 req.n.nlmsg_flags = NLM_F_REQUEST;
684 req.n.nlmsg_type = XFRM_MSG_FLUSHSA;
685 req.xsf.proto = IPSEC_PROTO_ANY;
686
687 if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
688 exit(1);
689
690 if (show_stats > 1)
691 fprintf(stderr, "Flush all\n");
692
693 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
694 exit(2);
695
696 rtnl_close(&rth);
697
698 return 0;
699}
700
c7699875 701int do_xfrm_state(int argc, char **argv)
702{
703 if (argc < 1)
704 return xfrm_state_list_or_flush(0, NULL, 0);
705
706 if (matches(*argv, "add") == 0)
707 return xfrm_state_modify(XFRM_MSG_NEWSA, 0,
708 argc-1, argv+1);
709 if (matches(*argv, "update") == 0)
710 return xfrm_state_modify(XFRM_MSG_UPDSA, 0,
711 argc-1, argv+1);
712 if (matches(*argv, "delete") == 0 || matches(*argv, "del") == 0)
713 return xfrm_state_get_or_delete(argc-1, argv+1, 1);
714 if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
715 || matches(*argv, "lst") == 0)
716 return xfrm_state_list_or_flush(argc-1, argv+1, 0);
717 if (matches(*argv, "get") == 0)
718 return xfrm_state_get_or_delete(argc-1, argv+1, 0);
bd641cd6 719 if (matches(*argv, "flush") == 0) {
720 if (argc-1 < 1)
721 return xfrm_state_flush_all();
722 else
723 return xfrm_state_list_or_flush(argc-1, argv+1, 1);
724 }
c7699875 725 if (matches(*argv, "help") == 0)
726 usage();
727 fprintf(stderr, "Command \"%s\" is unknown, try \"ip xfrm state help\".\n", *argv);
728 exit(-1);
729}