]> git.proxmox.com Git - mirror_iproute2.git/blob - ip/xfrm_state.c
[iproute2] XFRM: fixing IPsec algorithm key
[mirror_iproute2.git] / ip / xfrm_state.c
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
54 static void usage(void) __attribute__((noreturn));
55
56 static 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");
66 //fprintf(stderr, "XFRM_PROTO := [ esp | ah | ipcomp ]\n");
67 fprintf(stderr, "XFRM_PROTO := [ ");
68 fprintf(stderr, "%s | ", strxf_proto(IPPROTO_ESP));
69 fprintf(stderr, "%s | ", strxf_proto(IPPROTO_AH));
70 fprintf(stderr, "%s ", strxf_proto(IPPROTO_COMP));
71 fprintf(stderr, "]\n");
72
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
81 fprintf(stderr, "ALGO-LIST := [ ALGO-LIST ] | [ ALGO ]\n");
82 fprintf(stderr, "ALGO := ALGO_TYPE ALGO_NAME ALGO_KEY\n");
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
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
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
103 static 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;
107 int slen = strlen(key);
108
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
116 if (slen > 2 && strncmp(key, "0x", 2) == 0) {
117 /* 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.
126 */
127
128 /* 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);
132
133 for (i = - (plen % 2), j = 0; j < len; i += 2, j++) {
134 char vbuf[3];
135 char val;
136
137 vbuf[0] = i >= 0 ? p[i] : '0';
138 vbuf[1] = p[i + 1];
139 vbuf[2] = '\0';
140
141 if (get_u8(&val, vbuf, 16))
142 invarg("\"ALGOKEY\" is invalid", key);
143
144 alg->alg_key[j] = val;
145 }
146 } else {
147 len = slen;
148 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
161 static int xfrm_state_flag_parse(__u8 *flags, int *argcp, char ***argvp)
162 {
163 int argc = *argcp;
164 char **argv = *argvp;
165 int len = strlen(*argv);
166
167 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 }
179
180 filter.state_flags_mask = XFRM_FILTER_MASK_FULL;
181
182 *argcp = argc;
183 *argvp = argv;
184
185 return 0;
186 }
187
188 static 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) {
214 if (strcmp(*argv, "mode") == 0) {
215 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);
226 } else if (strcmp(*argv, "limit") == 0) {
227 NEXT_ARG();
228 xfrm_lifetime_cfg_parse(&req.xsinfo.lft, &argc, &argv);
229 } else {
230 /* 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;
245
246 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 }
299 }
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) {
312 fprintf(stderr, "\"ALGO\" is invalid with proto=%s\n", strxf_proto(req.xsinfo.id.proto));
313 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) {
319 fprintf(stderr, "\"ALGO\" is required with proto=%s\n", strxf_proto(req.xsinfo.id.proto));
320 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
338 static 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
366 static 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
375 static int xfrm_state_print(const struct sockaddr_nl *who,
376 const struct nlmsghdr *n,
377 void *arg)
378 {
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
410 fprintf(fp, "\t");
411 fprintf(fp, "replay-window %d ", xsinfo->replay_window);
412 if (show_stats > 0)
413 fprintf(fp, "seq 0x%08u ", xsinfo->seq);
414 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 }
423 }
424 }
425 fprintf(fp, "%s", _SL_);
426
427 xfrm_xfrma_print(tb, ntb, xsinfo->family, fp, "\t");
428
429 if (!xfrm_selector_iszero(&xsinfo->sel))
430 xfrm_selector_print(&xsinfo->sel, xsinfo->family, fp, "\tsel ");
431
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
437 if (oneline)
438 fprintf(fp, "\n");
439
440 return 0;
441 }
442
443 static 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));
474 xfrm_id_parse(&ignore_saddr, &id, &req.xsid.family, 0,
475 &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 */
517 static int xfrm_state_keep(const struct sockaddr_nl *who,
518 const struct nlmsghdr *n,
519 void *arg)
520 {
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
566 static int xfrm_state_list_or_flush(int argc, char **argv, int flush)
567 {
568 char *idp = NULL;
569 struct rtnl_handle rth;
570
571 filter.use = 1;
572 filter.xsinfo.family = preferred_family;
573
574 while (argc > 0) {
575 if (strcmp(*argv, "mode") == 0) {
576 NEXT_ARG();
577 xfrm_mode_parse(&filter.xsinfo.mode, &argc, &argv);
578
579 filter.mode_mask = XFRM_FILTER_MASK_FULL;
580
581 } else if (strcmp(*argv, "reqid") == 0) {
582 NEXT_ARG();
583 xfrm_reqid_parse(&filter.xsinfo.reqid, &argc, &argv);
584
585 filter.reqid_mask = XFRM_FILTER_MASK_FULL;
586
587 } else if (strcmp(*argv, "flag") == 0) {
588 NEXT_ARG();
589 xfrm_state_flag_parse(&filter.xsinfo.flags, &argc, &argv);
590
591 filter.state_flags_mask = XFRM_FILTER_MASK_FULL;
592
593 } else {
594 if (idp)
595 invarg("unknown", *argv);
596 idp = *argv;
597
598 /* ID */
599 xfrm_id_parse(&filter.xsinfo.saddr, &filter.xsinfo.id,
600 &filter.xsinfo.family, 1, &argc, &argv);
601 if (preferred_family == AF_UNSPEC)
602 preferred_family = filter.xsinfo.family;
603 }
604 argc--; argv++;
605 }
606
607 if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
608 exit(1);
609
610 if (flush) {
611 struct xfrm_buffer xb;
612 char buf[NLMSG_FLUSH_BUF_SIZE];
613 int i;
614
615 xb.buf = buf;
616 xb.size = sizeof(buf);
617 xb.rth = &rth;
618
619 for (i = 0; ; i++) {
620 xb.offset = 0;
621 xb.nlmsg_count = 0;
622
623 if (show_stats > 1)
624 fprintf(stderr, "Flush round = %d\n", i);
625
626 if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETSA) < 0) {
627 perror("Cannot send dump request");
628 exit(1);
629 }
630
631 if (rtnl_dump_filter(&rth, xfrm_state_keep, &xb, NULL, NULL) < 0) {
632 fprintf(stderr, "Flush terminated\n");
633 exit(1);
634 }
635 if (xb.nlmsg_count == 0) {
636 if (show_stats > 1)
637 fprintf(stderr, "Flush completed\n");
638 break;
639 }
640
641 if (rtnl_send(&rth, xb.buf, xb.offset) < 0) {
642 perror("Failed to send flush request\n");
643 exit(1);
644 }
645 if (show_stats > 1)
646 fprintf(stderr, "Flushed nlmsg count = %d\n", xb.nlmsg_count);
647
648 xb.offset = 0;
649 xb.nlmsg_count = 0;
650 }
651
652 } else {
653 if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETSA) < 0) {
654 perror("Cannot send dump request");
655 exit(1);
656 }
657
658 if (rtnl_dump_filter(&rth, xfrm_state_print, stdout, NULL, NULL) < 0) {
659 fprintf(stderr, "Dump terminated\n");
660 exit(1);
661 }
662 }
663
664 rtnl_close(&rth);
665
666 exit(0);
667 }
668
669 int do_xfrm_state(int argc, char **argv)
670 {
671 if (argc < 1)
672 return xfrm_state_list_or_flush(0, NULL, 0);
673
674 if (matches(*argv, "add") == 0)
675 return xfrm_state_modify(XFRM_MSG_NEWSA, 0,
676 argc-1, argv+1);
677 if (matches(*argv, "update") == 0)
678 return xfrm_state_modify(XFRM_MSG_UPDSA, 0,
679 argc-1, argv+1);
680 if (matches(*argv, "delete") == 0 || matches(*argv, "del") == 0)
681 return xfrm_state_get_or_delete(argc-1, argv+1, 1);
682 if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
683 || matches(*argv, "lst") == 0)
684 return xfrm_state_list_or_flush(argc-1, argv+1, 0);
685 if (matches(*argv, "get") == 0)
686 return xfrm_state_get_or_delete(argc-1, argv+1, 0);
687 if (matches(*argv, "flush") == 0)
688 return xfrm_state_list_or_flush(argc-1, argv+1, 1);
689 if (matches(*argv, "help") == 0)
690 usage();
691 fprintf(stderr, "Command \"%s\" is unknown, try \"ip xfrm state help\".\n", *argv);
692 exit(-1);
693 }